본문 바로가기

개인프로젝트(수강프로그램)

강좌신청

 

ResponseEntity- TakeCourse

 

public class TakeCourse {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    long courseId;
    String userId;

    long payPrice;
    String status;

    LocalDateTime regDt;
}

 

- TakeCourseRepository

 

public interface TakeCourseRepository extends JpaRepository<TakeCourse, Long> {


}

 

- 강좌 상세목록(detail.html)

 

서버에는 내 정보를 보내는 것이 아닌 어떤 강좌인지 id 값을 보낸다

 

<form id="submitForm" method="post">
    <input type="hidden" name="id" th:value="${detail.id}" />
    <button type="submit">수강신청</button>
    <a href="/course">강좌목록</a>
</form>

 

수강신청 버튼을 통해 서버로 데이터가 보내지는 ajax 사용, 서버에서는 api형태로 데이터를 받는다

 

axios의 post 기능을 이용해  url, id 값을 넣어준다

 

실제 찍힌 값

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script>

    $(function (){

        $('#submitForm').on('submit', function (){

            var $thisForm = $(this);

            var url = '/api/course/req.api';
            var parameter = {
                // 아이디 값은 hidden에 있는 thisForm의 id 값
                id: $thisForm.find('input[name=id]').val()
            };

            axios.post(url, parameter).then(function (response){

            }).catch(function (err){

            });

            return false;
        });

    });

</script>

 

- TakeCourseInput

 

@Data
public class TakeCourseInput {

    // courseId
    long courseId;
}

 

- ApiCourseController

 

@Controller는 String 을 사용하여 view를 리턴하지만 API서버 같은 경우에는 데이터만 바로 리턴한다

@Controller는 기본적으로 view페이지를 파일형태로 리턴

 

@RestController는 JsonBody로 데이터가 리턴되니 String이 아닌 responseEntity같은 값들이 리턴되어야 한다

이때는 ResponseEntity<?> 라는 값으로 리턴(문자열 리턴이 된다는 뜻)

 

public class ApiCourseController {

    private final CourseService courseService;
    private final CategoryService categoryService;

    @GetMapping("/api/course/req.api")
    public String courseRequest(Model model, TakeCourseInput param){




        return "course/index";
    }
}

 


@RequestBody로 보내지 않으면 payload로 값이 넘어가고 스프링부트에서 자동 

 

Principal : 유저정보를 가져올 수 있게 스프링 내부에서 지원하는 값

 

ResponseEntity로 상태값을 받을 수 있다

 

@RequiredArgsConstructor
@RestController
public class ApiCourseController extends BaseController{

    private final CourseService courseService;
    private final CategoryService categoryService;

    @PostMapping("/api/course/req.api")
    public ResponseEntity<?> courseRequest(Model model,
                                           @RequestBody TakeCourseInput param,
                                           Principal principal){

        // 유저정보 가져오는 코드
        param.setUserId(principal.getName());

        boolean result = courseService.request(param);

        if(!result){
            return ResponseEntity.badRequest().body("수강신청에 실패하셨습니다");
        }

        return ResponseEntity.ok().body(param);
    }
}

 

- CourseService

 

// 수강신청
 boolean request(TakeCourseInput param);

 

- CourseServiceImpl

 

@Override
public boolean request(TakeCourseInput param) {
    // 강좌글 id 가져오기
    Optional<Course> optionalCourse = courseRepository.findById(param.getCourseId());
    if(!optionalCourse.isPresent()){
        return false;
    }

    Course course = optionalCourse.get();

    TakeCourse takeCourse = TakeCourse.builder()
            .courseId(course.getId())
            .userId(param.getUserId())
            .payPrice(course.getSalePrice())
            .regDt(LocalDateTime.now())
            .build();

    takeCourseRepository.save(takeCourse);
    

    return true;
}

 


 

+) 트러블 슈팅

 

 

디버깅 모드에서 찍어보니 courseId 값이 null 로 들어왔다

 

이는 dto의 courseId 와 클라이언트 단의 id 객체명이 달라서 null로 들어옴

 

- detail.html

var parameter = {
    // 아이디 값은 hidden에 있는 thisForm의 id 값
    id: $thisForm.find('input[name=id]').val()
};

 

넘겨주는 id값과 dto(courseId )의 필드명이 같아야 한다

 


 

이제 상태값을 결정하는 엔티티 생성함

 

-TakeCourseCode

 

+ TakeCourse에 implement하기

public interface TakeCourseCode {

     String STATUS_REQ = "REQ"; // 수강 신청상태
     String STATUS_COM = "COM"; // 결제완료
     String STATUS_CANCEL = "CANCEL"; // 수강취소
    
}

 

- CourseServiceImpl

 

status값 저장

 

TakeCourse takeCourse = TakeCourse.builder()
        .courseId(course.getId())
        .userId(param.getUserId())
        .payPrice(course.getSalePrice())
        .regDt(LocalDateTime.now())
        .status(TakeCourse.STATUS_REQ)
        .build();

takeCourseRepository.save(takeCourse);

 

 

이미 신청되어있으면 신청이 안되는 로직 구현

 

- CourseRepository

 

public interface TakeCourseRepository extends JpaRepository<TakeCourse, Long> {

    // 값이 있는지 없는지 갯수로 판단
    long countByCourseIdAndUserIdAndStatusIn(long courseId, String userId, Collection<String> statusList);

}

 

- TakeCourseRepository

 

count 값이 있으면 이미 신청했거나 완료된 값이니 false 값을 준다

 

@Override
public boolean request(TakeCourseInput param) {

		...
    
    // 이미 신청한 경우 신청이 안되는 로직

    String[] statusList = {TakeCourse.STATUS_REQ, TakeCourse.STATUS_COM};

    long count = takeCourseRepository.countByCourseIdAndUserIdAndStatusIn(course.getId(),
            param.getUserId(), Arrays.asList(statusList));

    if (count > 0){
        return false;
    }

    

    return true;
}

 

상태값도 줬으니 각 상태 (수강신청시 Course 자체가 없는건지 데이터가 잘못되었는지에 대한) 에 대한 구체적인 에러값을 명시하는 로직이 필요


 

 

수강신청이 잘 되었는지 안되었느지, 실패했다면 어떤 문제때문에 실패하였느지 값처리

현재는 단순하게 boolean으로 true, false값만으로 처리

 

- ServiceResult

 

@Data
public class ServiceResult {

    boolean result;
    String message;
    
}

- CourseService

 

ServiceResult request(TakeCourseInput param);

 

- CourseServiceImpl

 

@Override
public ServiceResult request(TakeCourseInput param) {

    ServiceResult result = new ServiceResult();

    // 강좌글 id 가져오기
    Optional<Course> optionalCourse = courseRepository.findById(param.getCourseId());
    if(!optionalCourse.isPresent()){
        // 현재 에러는 강좌정보 자체가 없는것
        result.setResult(false);
        result.setMessage("강좌정보가 존재하지 않습니다");
        return result;
    }

    Course course = optionalCourse.get();

    // 이미 신청한 경우 신청이 안되는 로직

    String[] statusList = {TakeCourse.STATUS_REQ, TakeCourse.STATUS_COM};

    long count = takeCourseRepository.countByCourseIdAndUserIdAndStatusIn(course.getId(),
            param.getUserId(), Arrays.asList(statusList));

    if (count > 0){
        // 이미 신청한정보가 있을 때
        result.setResult(false);
        result.setMessage("이미 신청한 강좌정보가 있습니다");
        return result;
    }

    TakeCourse takeCourse = TakeCourse.builder()
            .courseId(course.getId())
            .userId(param.getUserId())
            .payPrice(course.getSalePrice())
            .regDt(LocalDateTime.now())
            .status(TakeCourse.STATUS_REQ)
            .build();

    takeCourseRepository.save(takeCourse);


    // 성공했을 때
    result.setResult(true);
    result.setMessage("");
    return result;
}

 

- ApiCourseController

 

@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()){
            return ResponseEntity.badRequest().body(result.getMessage());
        }

        return ResponseEntity.ok().body(param);
    }
}

 

- detail.html

 

<script>

    $(function (){

        $('#submitForm').on('submit', function (){

            if (!confirm("수강신청을 하시겠습니까?")) {
                return false;
            }

            var $thisForm = $(this);

            var url = '/api/course/req.api';
            var parameter = {
                // 아이디 값은 hidden에 있는 thisForm의 id 값
                courseId : $thisForm.find('input[name=id]').val()
            };

            axios.post(url, parameter).then(function (response){
                
                // data를 초기화시키는 자바스크립트 문법
                var msg = response.data || '';
                
                if (msg != ''){
                    alert(msg);
                }

            }).catch(function (err){

            });

            return false;
        });

    });

</script>

 


 

현재 에러메세지가 문자열로만 내려지는데 이를 제이슨을 사용하여 데이터 값으로 받아보겠다

 

 

- common.model.ResponeResult

@Data
public class ResponseResult {

    ResponseResultHeader header;
    Object body;


    public ResponseResult(boolean result, String message) {
        header = new ResponseResultHeader(result, message);
    }

    public ResponseResult(boolean result) {
        header = new ResponseResultHeader(result);
    }
}

 

- common.model.ResponeResultHeader

 

@Data
public class ResponseResultHeader {

    boolean result;
    String message;

    public ResponseResultHeader(boolean result, String message) {
        this.result = result;
        this.message = message;
    }

    public ResponseResultHeader(boolean result) {
        this.result = result;
    }
}

 

- ApiCourseController

 

@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(responseResult);
}

 

- 결과값

 

 

- detail.html

 

 

<script>

    $(function (){

        $('#submitForm').on('submit', function (){

            if (!confirm("수강신청을 하시겠습니까?")) {
                return false;
            }

            var $thisForm = $(this);

            var url = '/api/course/req.api';
            var parameter = {
                // 아이디 값은 hidden에 있는 thisForm의 id 값
                courseId : $thisForm.find('input[name=id]').val()
            };

            axios.post(url, parameter).then(function (response){

                // data를 초기화시키는 자바스크립트 문법
                var msg = response.data || '';

                // 객체로 초기화
               response.data = response.data || {};
               response.data.header = response.data.header || {};

               if(!response.data.header.result){
                   alert(response.data.header.message);
                   return false;
               }

               // 정상적 상황
               alert('강좌가 정상적으로 신청되었습니다');
               location.href = '/';

            }).catch(function (err){

            });

            return false;
        });

    });

</script>

 

 

 

 

'개인프로젝트(수강프로그램)' 카테고리의 다른 글

회원정보 수정  (0) 2022.05.03
백오피스 - 강좌신청 처리구현  (0) 2022.05.02
강좌 목록 구현  (0) 2022.04.25
강좌 목록 구현, 강좌 신청  (0) 2022.04.22
강좌목록  (0) 2022.04.20