origoni's Blog from Millky

origoni의 스프링 블로그 입니다.

[블로그개발_10] 글에 부제목 추가 (Post Entity 모델링 +lombok, @Valid)

블로그개발 시리즈 - 다른글 : http://millky.com/@origoni/folder/30/post/list

라이브 데모 : http://blog.millky.com/post/list

자바 웹 개발 시작하기 : http://www.slideshare.net/origoni/presentations




스프링(부트)을 이용한 자바 블로그 개발 글이 벌써 열번째 글이 되었다.

지금까지 아주 기초적인 스프링부트 프로젝트에 UI템플릿을 씌워 글을 작성하고 보여주는 부분까지 만들어 보았다.


오늘을 글을 저장하는데 사용되는 객체인 Post를 수정해보려 한다.

우리가 사용할 예정인 블로그 템플릿을 보니.. 부제목 표시하는 란이 있다.


부제목도 있으면 좋겠다고 생각해서 추가해 보려 한다.

부제목.. subtitle 라고 이름을 정하면 될 것 같다.


아래와 같이 추가하면 되겠다.

String subtitle;

public String getSubtitle() {
    return subtitle;
}
public void setSubtitle(String subtitle) {
    this.subtitle = subtitle;
}


우선 

String subtitle;

요렇게 적고. 마우스 오른쪽 버튼을 눌러서 




Source -> Generate Getters and Setters... 를 선택하여


쉽게(?) 추가 할 수 있다.

그럼 이제 아래와 같이 되었다.




그런데 이렇게 보니..


subject, subtitle.. 뭔가 조금 이상하다.

주제, 부제목. 음. 이상하구 주제를 제목(title)으로 바꿔야 하겠다.

그럼. 이제.  String subject; 는 String title; 로 바꾸고...

public String getSubject() {
    return subject;
}
public void setSubject(String subject) {
    this.subject = subject;
}

위의 게터세터는 지우고... 다시 만들면 간단하다... 고 생각한는가?


그나마 이클립스에서 게터세터를 자동으로 만들어 주기에 간단하다고 생각할 수는 있겠다.

하지만. 기본적인 자바빈즈 속성을 만들기 위해서 매번 Getter Setter 를 생성하는것은 매우 소모적인 일이 될 수 있겠다.

이런 일을 줄일 수 있을까?


그러기 위해 존재하는 lombok 이 있다. (Project Lombok : Spice up your java)

https://projectlombok.org/




사용을 하려면 pom.xml에 아래의 dependency를 추가하면 되겠다.

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.4</version>
</dependency>


그리고 이클립스에 설치해 줘야 한다.

https://projectlombok.org/download.html

요기서 다운 받아서 실행 후 STS 위치에 가서 설치할 수 있다.

Eclipse and variantsRun lombok.jar as a java app (i.e. doubleclick it, usually) to install. Also add lombok.jar to your project. Supported variants: Springsource Tool Suite, JBoss Developer Studio


인텔리제이는 따로 플러그인이 있다. 각자 사용하는 IDE에 맞게 설치하면 된다.

STS 3.7.0 (Eclipse Mars) 이상 사용하시는 분들은
OSX STS 3.7.0 (Eclipse Mars) 에서 Lombok 세팅하기 요글 참고 부탁드린다.


아까 그 길던 코드가 아래와 같이 줄었다..

@Getter
@Setter
@Entity
public class Post {
    @Id
    @GeneratedValue
    int id;
    String title;
    String subtitle;
    @Column(length = 100000000)
    String content;
    Date regDate;
}


여기서 이클립스의 아웃라인을 보면 있지도 않은 메서드들이 존재한다! 



이것말고 기본 생성자 만들기라던지.. features에 가보면 단순히 @Getter/@Setter 말고도 많은 기능들이 있다.

다른 기능들은 차차 알아가면 된다 ^^; (https://projectlombok.org/features/index.html 여기서~)


아래와 같이 UI를 적당히 수정하고..

<c:out value="${post.subtitle}" escapeXml="true"></c:out>

(c:out 요런간 나중에~~ 다시 이야기 할 시간이 있을....)




(음 스샷찍다 보니 list.jsp에 스킨 만들어주신 분이 벌써 <h2 class="post-title">, <h3 class="post-subtitle"> 이렇게 정의해주셨었군;;;)

돌려보자~



잘 나온다~


여기서 끝 하고 싶었지만. ㅋㅋㅋ

실수로 아무것도 작성안하고 저장 버튼을 눌러버리면... 아무것도 나오지 않게 된다는 사실을 알게 되었다. (너무 의도적인가? ㅋ)


물론 나중에 지우고 수정하고.. 하면 되고. 자바스크립트로 유효성 검사를 해도 되고... 하지만 지금은 자바 웹 개발 이야기를 하고 있으니 ㅋ 우리는 자바단에서 확인하도록 하겠다.

사실 위에 자바스크립트로 하면 된다고 적긴 했지만.

그냥 한 이야기 이고...

나는 기본적으로 브라우저에서 그냥 들어온 값을 신뢰하지 않는다.

간단한 툴을 가지고 손쉽게 POST 속성을 변경 가능하기 때문도 있고. 정말로 js 오작동이라던지. 네트워크나 다른 원인으로 잘못된 정보가 서버측으로 날아올 수 있기 때문이다.

그렇다고 자바스크립트로 유효성 검사 하지 말라는 말은 절대로 아니고. 둘다 필요하다는 말을 하는것이다.



바로 시작해보자.

우선. 원칙을 정해보자.

타이틀은... 꼭 필요하고.

서브타이틀은..... 옵션으로 하자.

컨텐츠는 널이 아니고.


이정도면 되려나?

잠깐 각 필드별로 최대 값이 얼마나 되는거지?

어서 h2콘솔에 붙어보자.

http://localhost:8080/console


아하 아래와 같다~


그럼 최대값도 저 이상 들어올 수 없게 막아보자!

방법은 간단하다.

Post 가서 위에 정한 값을 적어준다.

@NotNull
@Size(min = 1, max = 255)
@Column(nullable = false) // 위에 스샷찍고 보니 DB에 널 가능하기에. 이침에 수정하였다!
String title;
@Size(max = 255)
String subtitle;
@NotNull
@Size(min = 1, max = 100000000)
@Column(length = 100000000, nullable = false) // 여기도 nullable = false 추가!
String content;


그리고 컨트롤러에 가서 Post post 앞에 @Valid 붙여주면 된다~

@RequestMapping(value = "/write", method = RequestMethod.POST)
public String write(@Valid Post post) {
    post.setRegDate(new Date());
    return "redirect:/post/" + postDao.save(post).getId();
}


(물론 적어주고 @NotNull @Valid 등 적어주고 각각의 라이브러리를 임포트 하면 되다. 이클립스 에서는 Cmd(윈도우는 Ctrl ?) + Shift + o 누르면 필요한 라이브러리를 자동으로 import 해준다.)


이제 프로젝트를 띄워 아무것도 입력하지 말고 저장버튼을 눌러보자.

아래와 같이 에러가 400 발생하였다! (Whitelabel Error 포장은 다다다다음? 글쯤에 들어갈 예정이다 ^^;;)


There was an unexpected error (type=Bad Request, status=400).
Validation failed for object='post'. Error count: 1


음 적당하다. 이제 서버단에서 if를 사용하지 않고 간단한 무결성 체크가 가능하게 되었다~ 

우리는 표준 구현채(javax.validation.constraints.)에 있는것중 일부만 사용했지만 다른구현채 및 다른 어노테이션들도 있으니 필요한것들을 각자 추가해 서용하면 되겠다.




얼마전까지만해도 하이버네이트 벨리데이터를 사용했었다~     


...

여기서 끝을 낼까 했지만.

그래도 조금 더 보자.


사용자가 정말 잘못 입력할 수 있고.

때마침 우리가 만들어둔 자바스크립트가 오동작 할 수 있으니. 400에러 대신에 클라이언트 단으로 에러가 난 윈인을 전달해보다.


컨트롤러에 BindingResult를 추가해보자.

@RequestMapping(value = "/write", method = RequestMethod.POST)
public String write(@Valid Post post, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        return "form";
    }
    post.setRegDate(new Date());
    return "redirect:/post/" + postDao.save(post).getId();
}


요렇게 작성하면 된다.


그리고 form.jsp에 좀 할일이 있다.

스프링 폼 태그를 사용할 것이다.

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

태그라이브러리를 추가하고. (이부분도 나중에 커스텀 태그 작성하는 부분에서 심도있게~)


에러를 표시할 CSS를 추가하고.

.errorblock {border: 2px solid red;}
.error {color: red;}


폼 부분을 스프링 폼 태그에 맞추어 변경해보겠다.

<form:form action="/post/write" commandName="post" onsubmit="if($('#pen').html()!='<p><br></p>')$('#content').val($('#pen').html()); pen.destroy();" method="post">

    <form:errors path="*" cssClass="errorblock" element="div" />
    <form:input type="text" path="title" placeholder="Title"
        style="height: 70px; width: 100%; font-size: 55px; 
        border: none; border-right: 0px; border-top: 0px; boder-left: 0px; boder-bottom: 1px; outline-style: none; 
        font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; font-weight: 800;" />
    <form:errors path="title" cssClass="error" />
    <form:input type="text" path="subtitle" placeholder="Subtitle (option)"
        style="height: 60px; width: 100%; font-size: 24px; 
        border: none; border-right: 0px; border-top: 0px; boder-left: 0px; boder-bottom: 1px; outline-style: none; 
        font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; font-weight: 600;" />
    <hr style="margin-top: 2px; border-top: 1px solid #999;">
    <div data-toggle="pen" data-placeholder="Content" id="pen" style="min-height: 200px;"></div>
    <form:input type="hidden" path="content" id="content" />
    <form:errors path="content" cssClass="error" />
    <hr>
    <button type="submit" class="btn btn-primary btn-lg btn-block">저장</button>
</form:form>


스프링 폼 태그는...

일단 태그라이브러리 추가하고. 각 폼과 인풋 속성마다 form: 요거 붙여주고. name대신 path 로 변경해주고. commandName 설정을 해주면 된다.

자세한 내용은 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/view.html 참고 바란다.


이렇게 컨트롤러와 jsp가 준비가 되었으면 프로젝트를 다시 올려서 아무것도 입력하지 않고 저장을 해보자!


이렇게 나오면 성공이다.

참고로 여기 나오는 '크기는 반드시~' 이부분 당연하게 커스터마이징 가능하다. 해당 부분은 나중에 국제화(i18n) 하면서 다뤄보도록 하겠다.


수고하셨습니다.



오늘은 크게 lombok, @Valid 에 대해 알아보았다.

사실 나는 스프링 폼 태그까지는 사용하지 않는다.

자바스크립트가 거의 동작할 것이고...

@Valid 실패하더라도 통합 에러 페이지에서 잘 표시해 주는 정도로 마무리 한다.

각자의 취향에 맞추어, 서비스 스펙에 맞추어 유동적으로 작업 해주면 될 것 같다.


그리고. 오늘 분명 Post를 수정했는데.. DB 저장하는 어떠한 부분도 수정한 것이 없다는 사실을 기억해주면 좋겠다.

물론 기능이 늘어나면서 Entity 수정에 따라 레파지토리를 변경할 일들이 생기겠지만. 이전(?) 만큼을 아닐 것이다.


오늘 작업한 코드는 https://github.com/origoni/Spring-Blog/releases/tag/v0.0.10 여기를 참고 부탁드린다.


변경사항은 : https://github.com/origoni/Spring-Blog/commit/b4fe15ba3aa6ddd28d763bbc7e3a19e75c5c486e

깃헙 : https://github.com/origoni/Spring-Blog

프로젝트 시작하는 방법은(for Windows User)? http://millky.com/@origoni/post/1145

블로그개발 시리즈 - 다른글 : http://millky.com/@origoni/folder/30/post/list



back to top