관리자 페이지에서 수강신청 목록을 보는 로직 구현
수강내역을 확인하고 승인 구현
+) 트러블슈팅
- ApiCourseController
강좌신청시 유저정보를 위해 Principal을 사용하여 로그인한 유저정보를 가져왔는데 id값을 가져오는 것이 아닌 username을 받아오는 에러가 발생
왜 이 오류에 직면했나?
관리자모드에서 수강관리에 대한 정보를 가져올때 member에 있는 userId와 takecourse에 있는 userId가 같은 것을 조회했는데
아래의 코드처럼 Principal을 사용해서 로그인정보를 가져왔는데 Db에 username이 저장되는 문제가 발생
@PostMapping("/api/course/req.api")
public ResponseEntity<?> courseRequest(Model model,
@RequestBody TakeCourseInput param,
Principal principal){
// 유저정보 가져오는 코드
param.setUserId(principal.getName());
ServiceResult result = courseService.request(param);
if (!result.isResult()){
ResponseResult responseResult = new ResponseResult(false, result.getMessage());
return ResponseEntity.ok().body(responseResult);
}
// 내리는 값자체를 param이 아닌 response 값 자체를 내릴것
ResponseResult responseResult = new ResponseResult(true);
return ResponseEntity.ok().body(param);
}
문제를 해결하기 위해 구글링을 한 결과 스프링 시큐리티에서 값을 가져올때 문제가 있다고 판단했고 실제 memberServiceImpl을 보니 username으로 받아오고 있었다...
이를 id로 바꿔주니 해결!
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<Member> optionalMember = memberRepository.findById(username);
if(!optionalMember.isPresent()){
throw new UsernameNotFoundException("회원정보가 존재하지 않습니다");
}
Member member = optionalMember.get();
// 이메일 인증절차에 관한 로직
// true가 아닐때 예외처리
if(Member.MEMBER_STATUS_REQ.equals(member.getUserStatus())){
throw new MemberNotEmailAuthException("이메일 활성화 이후에 로그인 진행해주세요");
}
if(Member.MEMBER_STATUS_STOP.equals(member.getUserStatus())){
throw new MemberStopUserlAuthException("정지된 회원입니다");
}
// return 객체의 파라미터가 이름, 비밀번호 , role인데 role은 직접 설정해야함
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
// 유저과 관리자일때 관리자 역할 부여
if(member.isAdminYn()){
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
// !!!!!!!!!! 여기가 문제 username으로 받아옴
return new User(member.getUserName(), member.getPassword(),grantedAuthorities);
}
- 수강관리메뉴
어떤 강좌에 대해서 사용자 정보가 나오도록 쿼리를 작성해야 한다
- AdminTakeCourseController
기존 강좌 리스트와 비슷한 구조이며 후에 들어갈 쿼리빼고 대부분 비슷함
@RequiredArgsConstructor
@Controller
public class AdminTakeCourseController extends BaseController{
private final TakeCourseService takeCourseService;
@GetMapping("/admin/takecourse/list")
public String list(Model model, TakeCourseParam param){
param.init();
List<TakeCourseDto> courseList = takeCourseService.list(param);
long totalCount = 0;
if(courseList != null && courseList.size() > 0){
totalCount = courseList.get(0).getTotalCount();
}
String queryString = param.getQueryString();
String pagerHtml = getPapaerHtml(totalCount, param.getPageSize(), param.getPageIndex(), queryString);
model.addAttribute("list", courseList);
model.addAttribute("pager", pagerHtml);
model.addAttribute("totalCount", totalCount);
return "admin/takecourse/list";
}
}
- TakeCourseService
public interface TakeCourseService {
// 수강목록
List<TakeCourseDto> list(TakeCourseParam param);
}
- TakeCourseParam
@Data
public class TakeCourseParam extends CommonParam {
}
- TakeCourseDto
TakeCourse 엔티티에 있는 내용을 가져올 거임
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class TakeCourseDto {
long id;
long courseId;
String userId;
long payPrice;
String status;
LocalDateTime regDt;
// 조인컬럼
String userName;
String phone;
String subject;
// 페이징 카운트트
long totalCount;
long seq;
}
- TakeCourseServiceImpl
@RequiredArgsConstructor
@Service
public class TakeCourseServiceImpl implements TakeCourseService{
private final TakeCourseMapper takeCourseMapper;
@Override
public List<TakeCourseDto> list(TakeCourseParam param) {
long totalCount = takeCourseMapper.selectListCount(param);
List<TakeCourseDto> list = takeCourseMapper.selectList(param);
// 각 칼럼에 totalCount를 넣어주는 식
if(!CollectionUtils.isEmpty(list)){
int i = 0;
for (TakeCourseDto m : list){
m.setTotalCount(totalCount);
m.setSeq(totalCount - param.getPageStart() - i);
i++;
}
}
return list;
}
}
- TakeCourseMapper
@Mapper
public interface TakeCourseMapper {
long selectListCount(TakeCourseParam param);
List<TakeCourseDto> selectList(TakeCourseParam param);
}
- TakeCourseMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zerobase.fastlms.course.mapper.TakeCourseMapper">
<!-- 공통인 부분 처리, 중복 쿼리를 줄이기 위해 사용-->
<sql id="selectListWhere">
</sql>
<select id="selectListCount"
parameterType="com.zerobase.fastlms.course.model.TakeCourseParam"
resultType="long">
select count(*)
from take_course
where 1 = 1
<include refid="selectListWhere" />
</select>
<select id="selectList"
resultType="com.zerobase.fastlms.course.dto.TakeCourseDto">
select tc.*
, c.subject
, m.user_name
, m.phone
from take_course tc
join course c on tc.course_id = c.id
join member m on tc.user_id = m.user_id
where 1 = 1
<include refid="selectListWhere" />
order by reg_dt desc
limit #{pageStart}, #{pageEnd}
</select>
</mapper>
- detail.html
<div class="list">
<div class="buttons">
<p class="total-count">전체 <span th:text="${totalCount}"></span>개</p>
</div>
<table>
<thead>
<tr>
<th>
<input id="selectAll" type="checkbox" />
</th>
<th> NO </th>
<th>
등록일
</th>
<th>
강좌명
</th>
<th colspan="3">
신청인
</th>
<th>
상태
</th>
</tr>
</thead>
<tbody id="dataLIst">
<tr th:each="x : ${list}">
<td>
<input type="checkbox" th:value="${x.id}" />
</td>
<td th:text="${x.seq}">1</td>
<td>
<p th:text="${x.regDt}">2021.01.01</p>
</td>
<td>
<p th:href="'edit?id=' + ${x.id}" th:text="${x.subject}">강좌명</p>
</td>
<td>
<p th:text="${x.userName}"></p>
</td>
<td>
<p th:text="${x.userId}"></p>
</td>
<td>
<p th:text="${x.phone}"></p>
</td>
<td>
<p th:if="${x.status eq 'REQ'}">수강신청</p>
<p th:if="${x.status eq 'COM'}">결제완료</p>
<p th:if="${x.status eq 'CANCEL'}">수강취소</p>
</td>
</tr>
</tbody>
</table>
<div class="pager" th:utext="${pager}">
</div>
</div>
<form name="deleteForm" method="post" action="/admin/course/delete">
<input type="hidden" name="idList"/>
</form>
</body>
</html>
상태를 결제완료 처리하는 로직
- detail
<tbody id="dataLIst">
<tr th:each="x : ${list}">
<td>
<input type="checkbox" th:value="${x.id}" />
</td>
<td th:text="${x.seq}">1</td>
<td>
<p th:text="${x.regDt}">2021.01.01</p>
</td>
<td>
<p th:href="'edit?id=' + ${x.id}" th:text="${x.subject}">강좌명</p>
</td>
<td>
<p th:text="${x.userName}"></p>
</td>
<td>
<p th:text="${x.userId}"></p>
</td>
<td>
<p th:text="${x.phone}"></p>
</td>
<td>
<p th:if="${x.status eq 'REQ'}">수강신청</p>
<p th:if="${x.status eq 'COM'}">결제완료</p>
<p th:if="${x.status eq 'CANCEL'}">수강취소</p>
</td>
<td>
// 수강신청일때만 결제완료 , 수강취소 처리가 보이도록 설정
<p th:if="${x.status eq 'REQ'}">수강신청
<button type="button">결제완료 처리</button>
<button type="button">수강취소 처리</button>
</p>
</td>
</tr>
</tbody>
</table>
<div class="pager" th:utext="${pager}">
</div>
</div>
// 수강상태를 id, status값으로 서버에 ajax처리 후 넘겨준다
<form name="proForm" method="post" action="/admin/takecourse/status">
<input type="hidden" name="id"/>
<input type="hidden" name="status"/>
</form>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script>
$(document).ready(function() {
// 여기서의 button은 수강완료가 될수도 있고 수강취소가 될 수도 있다
$('.row-buttons button').on('click', function (){
var status = $(this).val();
// this = row-buttons, 상위 div로 올라가서 input의 name이 id인것을 find
var id = $(this).closest('div').find('input[name=id]').val();
var msg = status == 'COMPLETE' ? '결제완료처리 하시겠습니까?' : '수강처리취소 하시겠습니까';
if(!confirm(msg)){
return false;
}
// proForm데이터 가져오기
var $proForm = $('#proForm');
$proForm.find('input[name=id]').val(id);
$proForm.find('input[name=status]').val(status);
$proForm.submit();
});
});
</script>
- AdminTakeCourseController
@PostMapping("/admin/takecourse/status")
public String status(Model model, TakeCourseParam param){
ServiceResult result = takeCourseService.updateStatus(param.getId(), param.getStatus());
if(!result.isResult()){
model.addAttribute("message", result.getMessage());
return "common/error";
}
return "redirect:/admin/takecourse/list";
}
- TakeCourseParam
html에서 ajax로 넘겨준 id와 status를
TakeCourseParam으로 받아준다
@Data
public class TakeCourseParam extends CommonParam {
long id;
String status;
}
- TakeCourseService
// 수강내용 상태변경
ServiceResult updateStatus(long id, String status);
- TakeCourseServiceImpl
@Override
public ServiceResult updateStatus(long id, String status) {
Optional<TakeCourse> optionalTakeCourse = takeCourseRepository.findById(id);
if (!optionalTakeCourse.isPresent()){
return new ServiceResult(false, "수강정보가 존재하지 않습니다");
}
TakeCourse takeCourse = optionalTakeCourse.get();
takeCourse.setStatus(status);
takeCourseRepository.save(takeCourse);
return new ServiceResult(true);
}
+ ) 등록일 수정
- TakeCourseDto
public String getRegDtText(){
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
return regDt != null ? regDt.format(formatter) : "";
}
'개인프로젝트(수강프로그램)' 카테고리의 다른 글
강좌관리 (0) | 2022.05.12 |
---|---|
회원정보 수정 (0) | 2022.05.03 |
강좌신청 (0) | 2022.04.25 |
강좌 목록 구현 (0) | 2022.04.25 |
강좌 목록 구현, 강좌 신청 (0) | 2022.04.22 |