Spring Framework-8

유호준·2021년 3월 19일
0

Spring Framework

목록 보기
9/21

😀이번엔 회원 시스템을 만들어보자!
그동안은 모두 비로그인 방식으로 처리를 했지만 글 수정, 삭제는 글의 작성자만 할 수 있어야 합니다. 따라서 로그인과 회원가입을 만들어보도록 하겠습니다. 이번에는 @RestController로 구현하겠습니다.

RESTful

RESTRepresentational State Transfer의 약자로 자원이름(자원의 표현)으로 구분하여 해당 자원의 상태(정보)를 주고 받는 모든 것을 의미합니다.
RESTfulREST 아키텍처의 제약 조건을 준수하는 것을 RESTful하다고 합니다.
우리는 RESTful하게 맞추기는 어려우니 HTTP의 메소드로 행위를 구분짓는 것만 할 것입니다. GETPOST는 자원을 얻는 것, 자원을 생성하는 것을 의미하고 PUT은 전체적인 수정, PATCH는 부분적인 수정을 할 때 사용합니다. 마지막으로 DELETE는 삭제를 할 때 사용합니다. EX) GET요청으로 /post/1 → post 1번을 보내줘!, DELETE요청으로 → /post/1 post 1번을 삭제해줘! 등등..

RESTful 제약조건

  • Client-Server
  • Stateless
  • cache
  • uniform interface
    1. identification of resources
    2. manipulation of resources through representation
    3. self-descriptive messages
    4. hypermedia as the engine of application state
  • layered system
  • code-on-demand

왜 @RestController를 써야할까?

우리는 지금까지 서버에서 View와 함께 정보를 업데이트했습니다. 하지만 우리는 정보만 받고 싶을 수도 있습니다. 이럴 때 사용하는게 @RestControllerajax를 이용하여 비동기 통신을 합니다. @RestController@Controller+@ResponseBody입니다.


View 수정

login.jsp 추가

테마에 있는 login.html을 복사하여서 정적 자원의 주소를 절대 주소로 바꾸고 jsp 형식으로 변경하여 줍니다. 그리고 Create an Account!를 누르면 회원가입 페이지가 나오도록 수정합니다.

register.jsp 추가

회원가입을 진행할 register.jsp를 추가합니다. form을 아래와 같이 수정하고 Already have an account? Login!를 누르면 로그인 페이지로 갈 수 있게 경로를 수정합니다. 그리고 아래 스크립트도 추가합니다.

<script>
    $("#register").click(function(){
        if(nullCheck())
            return
        else if(!($("[name='password']").val()==$("[name='repeatPassword']").val())) {
            alert("비밀번호와 비밀번호 확인이 맞지 않습니다.")
            $("[name='password']").focus()
        }
        else{
            var userVO = new Object()
            userVO.name = $("[name='name']").val()
            userVO.password = $("[name='password']").val()
            userVO.email = $("[name='email']").val()

            $.ajax({
                url:"/user",
                type:"POST",
                data:JSON.stringify(userVO),
                contentType:"application/json;charset=UTF-8",
                success:function (data) {
                    if(data.error==null)
                        location.href = "/login"

                    else if(data.error === "duplication")
                        alert("email이 중복됩니다.")

                }
            })
        }
    })

    function nullCheck() {
        if($("[name='name']").val()==""){
            alert("이름을 입력해주세요.")
            $("[name='name']").focus()
            return true
        }
        if($("[name='email']").val()==""){
            alert("email을 입력해주세요.")
            $("[name='email']").focus()
            return true
        }
        if($("[name='password']").val()==""){
            alert("비밀번호을 입력해주세요.")
            $("[name='password']").focus()
            return true
        }
        if($("[name='repeatPassword']").val()==""){
            alert("비밀번호 확인을 입력해주세요.")
            $("[name='repeatPassword']").focus()
            return true
        }
        return false
    }
</script>

이번에는 폼에서 제대로 이름, email, 비밀번호를 입력하였는지 확인하고, 비밀번호비밀번호 확인이 맞는지 확인 후에 ajax로 서버에 요청을 보내도록 스크립트를 작성합니다. 그리고 요청이 성공적으로 끝난 후에 반환된 값에 error가 없을 경우 로그인 화면으로 연결하고 error가 있고 그 errorduplication이라는 문자열이면 email이 중복되었다고 알려줍니다.


DB 수정

유저의 정보를 저장할 user 테이블을 생성합니다.

create table user(
    id int primary key not null auto_increment,
    name varchar(10),
    password varchar(20),
    email varchar(100)
)

UserVO 추가

user의 정보를 담을 UserVO를 추가합니다.

@Data
public class UserVO {
    private int id;
    private String name;
    private String password;
    private String email;
}

mybatis-config.xml 수정

UserVOalias를 추가하기 위해 mybatis-config.xml을 수정해 줍니다.

<configuration>

    <typeAliases>
        <typeAlias type="ac.kr.smu.vo.PostVO" alias="PostVO"/>
        <typeAlias type="ac.kr.smu.vo.UserVO" alias="UserVO"/>
    </typeAliases>

</configuration>

UserMapper 인터페이스와 xml추가

user관련 처리를 하는 UserMapper 인터페이스와 xml을 추가합니다.
checkEmailDuplication은 파라미터로 들어온 email을 가진 user가 저장되있는지 확인합니다.

<mapper namespace="ac.kr.smu.mapper.UserMapper">
    <insert id="save">
        INSERT INTO user(name,email,password)
        VALUES (#{name},#{email},#{password})
    </insert>

    <select id="checkEmailDuplication" resultType="int">
        SELECT COUNT(*) FROM user where email=#{email}
    </select>
</mapper>
public interface UserMapper {
    public void save(UserVO userVO);
    public int checkEmailDuplication(String email);
}

UserService 인터페이스와 UserServiceImpl 추가

UserService 인터페이스와 이를 구현한 UserServiceImpl 클래스를 추가합니다. checkEmailDuplication

public interface UserService {
    public void save(UserVO userVO)
    public boolean checkEmailDuplication(String email)
}
@RequiredArgsConstructor
@Service
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;

    @Override
    public void save(UserVO userVO) {
        userMapper.save(userVO);
    }

    @Override
    public boolean checkEmailDuplication(String email) {
        return userMapper.checkEmailDuplication(email)==0;
    }
}

@RequiredArgsConstructorlombokAnnotation으로 필수로 필요한 필드들을 포함하는 생성자를 만들어줍니다. 그리고 이 객체는 Spring에 의해 만들어지므로 의존성 주입이 되어서 @Autowired를 붙인 것과 같게 됩니다. 저는 이 방법이 더 깔끔해서 선호합니다.


UserController, LoginController 추가

하기 전에 이제 필요없는 TestController 클래스를 삭제합니다. 이제 기본적으로 로그인 화면이 나오게 할 것입니다.

LoginController 추가

이번에는 @RestController를 사용하기 때문에 String을 반환하면 그냥 문자열을 반환하는 것과 같고 void라면 아무것도 반환하지 않습니다. 따라서 우리가 직접 view를 반환해줘야합니다. 그래서 ModelAndView(ModelView를 함께 가진 객체)

@RestController
@RequiredArgsConstructor
@RequestMapping("/")
public class LoginController {
    @GetMapping
    public ModelAndView getLogin(){
        return new ModelAndView("login");
    }
}

여기서는 사실 @Controller를 사용하는게 맞겠지만, @RestController에 익숙해지기 위해 일부러 사용했습니다.

@Controller와 @RestController의 차이

@Controller

@Controller
@RequestMapping("/login")
public class LoginController {
    @GetMapping
    public void getLogin(){}
}


@RestController

@RestController
@RequestMapping("/login")
public class LoginController {
    @GetMapping
    public void getLogin(){}
}


위처럼 View가 반환되지 않기 때문에 아무것도 나오지 않습니다.

UserController 추가

user관련 처리를 하는 UserController를 추가해줍니다. postUser에서는 user를 추가하기 전에 email을 검사해서 있다면 중복되었다는 에러를 반환합니다. 없다면 저장하고 에러에 null을 넣고 반환합니다.

@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;

    @GetMapping
    public ModelAndView getUser(){
        return new ModelAndView("register");
    }

    @PostMapping
    public Map<String,String> postUser(@RequestBody UserVO userVO){
        Map<String, String> result = new HashMap<>();

        if(!userService.checkEmailDuplication(userVO.getEmail())){
            result.put("error","duplication");
            return result;
        }

        userService.save(userVO);
        result.put("error",null);
        return result;
    }
}

여기에서도 getUser() 메소드가 통상적으로는 user 목록을 반환하는 등의 user의 정보를 반환하는 게 맞습니다.


테스트

원래는 비밀번호는 암호화되어야 합니다. 이는 후에 Spring Security에서 다룰 것입니다.






0개의 댓글