다국어 지원을 위해 UTF-8 을 기본 Encoding 으로,
org.springframework.web.filter.CharacterEncodingFilter
을 등록 한다.
만약 Tomcat 을 사용하는 경우, server.xml 의 <Connector>에 URIEncoding="UTF-8" 요소도 추가하여야 한다.
<!-- ########################################## # CharacterEncodingFilter ########################################## --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <servlet-name>appServlet</servlet-name> </filter-mapping>
RESTful URL을 사용하기 위해,
org.springframework.web.filter.HiddenHttpMethodFilter
을 등록 한다.
<!-- ########################################## # http MethodFilter ########################################## --> <filter> <filter-name>httpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>httpMethodFilter</filter-name> <servlet-name>appServlet</servlet-name> </filter-mapping>
multipart 지원을 위해
org.springframework.web.multipart.support.MultipartFilter
을 등록 한다.
<!-- ########################################## # MultipartFilter ########################################## --> <filter> <filter-name>multipartFilter</filter-name> <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class> </filter> <filter-mapping> <filter-name>multipartFilter</filter-name> <servlet-name>appServlet</servlet-name> </filter-mapping>
Spring Context 와
Spring-Security
의 Locale 설정을 통일하기 위해
com.u2ware.springfield.support.i18n.LocaleChangeFilter
을 등록 한다.
<!-- ########################################## # LocaleChangeFilter ########################################## --> <filter> <filter-name>localeChangeFilter</filter-name> <filter-class>com.u2ware.springfield.support.i18n.LocaleChangeFilter</filter-class> </filter> <filter-mapping> <filter-name>localeChangeFilter</filter-name> <servlet-name>appServlet</servlet-name> </filter-mapping>
Spring-Security
지원을 위해
org.springframework.web.filter.DelegatingFilterProxy
을 등록 한다.
<!-- ########################################## # springSecurityFilterChain ########################################## --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <servlet-name>appServlet</servlet-name> </filter-mapping>
Section 1.3, “<springfield:modules>” 은 등록된
EntityController
의 handler method 룰 RESTful 요청 경로로 매핑 한다.
Section 1.2, “@Springfield” 의 topLevelMapping 속성을 설정하여 요청 경로를 변경할 수 있으며,
별도의 선언 이 없으면, basePackage 를 기준으로 결정된다.
요청 경로에 따른 응답 view name 은 EntityController 의 메소드 이름이 조립되어 문자열로 리턴된다.
Table 3.1. Request mapping. See Section 1.4, “Springfield Example”
handle method | HTTP Method | Request Path | Response ViewName |
---|---|---|---|
fooController.find() | GET | /foo | "/foo/find" |
fooController.read() | GET | /foo/1 | "/foo/read" |
fooController.createForm() | GET | /foo/new | "/foo/createForm" |
fooController.create() | POST | /foo/new | "/foo/create" |
fooController.updateForm() | GET | /foo/1/edit | "/foo/updateForm" |
fooController.update() | PUT | /foo/1/edit | "/foo/update" |
fooController.delete() | DELETE | /foo/1/edit | "/foo/delete" |
barSearchController.find() | GET | /a/b/c/d | "/a/b/c/d/find" |
barSearchController.read() | GET | /a/b/c/d/1 | "/a/b/c/d/read" |
barSearchController.createForm() | GET | /a/b/c/d/new | "/a/b/c/d/createForm" |
barSearchController.create() | POST | /a/b/c/d/new | "/a/b/c/d/create" |
barSearchController.updateForm() | GET | /a/b/c/d/1/edit | "/a/b/c/d/updateForm" |
barSearchController.update() | PUT | /a/b/c/d/1/edit | "/a/b/c/d/update" |
barSearchController.delete() | DELETE | /a/b/c/d/1/edit | "/a/b/c/d/delete" |
요청 매핑은 Section 1.2, “@Springfield” 의 methodLevelMapping 속성값에 의해 결정된다.
methodLevelMapping 에서
EntityController
의 handler method 이름과 확장자를 선언 하는 방식으로 요청 매핑을 추가, 변경 할수 있다.
이때, 선언가능한 확장자는 Table 3.2, “Extension Based Resolving views” 과 같다.
와일드카드는
EntityController
의 모든 handler method 를 의미하며,
별도의 선언이 없으면 default 로 {*} 가 등록된다.
// package com.yourcompany.yourproject.foo; @Springfield @Entity public class Foo{ @Id private String name; private Integer age; ... }
Controller method() | HTTP Method | Request Path | Response ViewName |
---|---|---|---|
fooController.find() | GET | /foo | "/foo/find" |
fooController.read() | GET | /foo/1 | "/foo/read" |
fooController.createForm() | GET | /foo/new | "/foo/createForm" |
fooController.create() | POST | /foo/new | "/foo/create" |
fooController.updateForm() | GET | /foo/1/edit | "/foo/updateForm" |
fooController.update() | PUT | /foo/1/edit | "/foo/update" |
fooController.delete() | DELETE | /foo/1/edit | "/foo/delete" |
// package com.yourcompany.yourproject.foo; @Springfield @Entity( methodLevelMapping={ "find", "find.html", "find.json", "read", "read.html", "read.json" } ) public class Foo{ @Id private String name; private Integer age; ... }
Controller method() | HTTP Method | Request Path | Response ViewName |
---|---|---|---|
fooController.find() | GET | /foo | "/foo/find" |
/foo.html | "/foo/find.html" | ||
/foo.json | "/foo/find.json" | ||
fooController.read() | GET | /foo/1 | "/foo/read" |
/foo/1.html | "/foo/read.html" | ||
/foo/1.json | "/foo/read.json" |
// package com.yourcompany.yourproject.foo; @Springfield @Entity( methodLevelMapping={"*.jstl"} ) public class Foo{ @Id private String name; private Integer age; ... }
Controller method() | HTTP Method | Request Path | Response ViewName |
---|---|---|---|
fooController.find() | GET | /foo.jstl | "/foo/find.jstl" |
fooController.read() | GET | /foo/1.jstl | "/foo/read.jstl" |
fooController.createForm() | GET | /foo/new.jstl | "/foo/createForm.jstl" |
fooController.create() | POST | /foo/new.jstl | "/foo/create.jstl" |
fooController.updateForm() | GET | /foo/1/edit.jstl | "/foo/updateForm.jstl" |
fooController.update() | PUT | /foo/1/edit.jstl | "/foo/update.jstl" |
fooController.delete() | DELETE | /foo/1/edit.jstl | "/foo/delete.jstl" |
Section 1.3, “<springfield:modules>”에 의해
EntityController
가 등록되는 경우 ViewName 을 랜더링하기 위해 다음 과 같은 View Resolver Bean 들이 자동 등록된다.
ViewName 의 확장자를 추출하여, 해당하는 View Resolver 를 찾아서 랜더링을 위임한다.
확장자가 없는 경우,
Thymeleaf
가 디폴트로 적용된다.
Table 3.2. Extension Based Resolving views
Extension | View Resolver Bean Name | operations |
---|---|---|
*.html | springfieldWebmvcRenderThymeleafViewResolver | Thymeleaf |
*.jstl | springfieldWebmvcRenderJstlViewResolver | JSP |
*.tiles | springfieldWebmvcRenderTilesViewResolver | Tiles2 |
*.json | springfieldWebmvcRenderJsonViewResolver | JSON View |
*.xml | springfieldWebmvcRenderXmlViewResolver | XML View |
*.xls | springfieldWebmvcRenderXlsViewResolver | Excel View |
*.csv | springfieldWebmvcRenderCsvViewResolver | CSV View |
*.download | springfieldWebmvcRenderDownloadViewResolver | File Download View |
*.stream | springfieldWebmvcRenderStreamViewResolver | File Streaming View |
Section 1.3, “<springfield:modules>” 가 지원하는 Thymeleaf는 Rendering 을 위한 정적인 리소스(html, jsp)를 추가하여 Customizing 할수 있다. runtime 에 미리 정해진 위치를 스캔하여 정적인 리소스가 존재하면 이를 사용 한다. 만약 해당 위치에 정적인 리소스가 없다면, <springfield:moduls> 가 기본제공하는 Thymeleaf 페이지가 사용 된다. 리소스 검색 위치 순서는 다음과 같다.
@Springfield(toplevelMapping="/sample") @Entity public class Sample { @Id private Integer intValue; private String stringValue; private Float floatValue; private DateTime dateTimeValue; //... }
다음과 같이 /WEB-INF/com/yourcompany/yourproject/sample/find.html 을 작성하고,
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"> <h1>My Themyleaf Page</h1> </html>
[GET:/sample] 요청 일때, 위 리소스를 리턴한다.
Section 1.3, “<springfield:modules>” 은 JSON View 를 위해
jackson 및
jackson-annotations 을
를 사용하고 있다. property name 을 바꾸기 위해
@JsonProperty
를 사용하거나 ,
해당 property 를 출력하지 않도록 @JsonIgnore
를 사용할수 있다.
@Springfield(toplevelMapping="/sample", methodLevelMapping={"*.json"}) @Entity public class Sample { @Id private Integer intValue; @JsonProperty("newPropertyName") private String stringValue; @JsonIgnore private Float floatValue; private DateTime dateTimeValue; //... }
[GET:/sample/{intValue}.json] 요청 일때 , 다음과 같은 JSON Content 를 리턴 한다.
{ "intValue":1, "newPropertyName":"abcd" "dateTimeValue":"2011-01-01T00:00:00.000+09:00", }
Section 1.3, “<springfield:modules>” 은 Excel View 를 위해
jExcelApi 를 사용하고 있다.
Excel 의 Herder 셀의 명칭을 바꾸기 위해
@XlsProperty
를 사용하거나 ,
해당 property 를 출력하지 않도록
@XlsIgnore
를 사용할수 있다.
@Springfield(toplevelMapping="/sample", methodLevelMapping={"*.xls"}) @Entity public class Sample { @Id private Integer intValue; @XlsProperty("새이름") private String stringValue; @XlsIgnore private Float floatValue; private DateTime dateTimeValue; //... }
[GET:/sample.xls] 요청 일때, 다음과 같은 Excel Sheet 를 응답한다.
** Response Sheet +----------+-------------+---------------+ | intValue | 새이름 | dateTimeValue | +----------+-------------+---------------+ | 1 | a | 2010-01-01 | +----------+-------------+---------------+ | 1 | b | 2010-01-01 | +----------+-------------+---------------+
Section 1.3, “<springfield:modules>”의 Excel View 는 runtime 에 미리 정해진 위치를 스캔하여 Template File 이 존재하면 이를 parsing 하여 응답 한다.
Template File 은
Spring Expression Language (SpEL)
문법을 따른다.
Template File 이 사용될 경우
@XlsProperty
와
@XlsIgnore
는 모두 무시된다.
Template File 검색 위치 순서는 다음과 같다.
다음과 같이 /WEB-INF/com/yourcompany/yourproject/sample/read.xls 을 작성하고,
** Template Sheet +--------+------------------+ | 정수 | #{intValue} | +--------+------------------+ | 문자 | #{stringValue} | +--------+------------------+ | 실수 | #{floatValue} | +--------+------------------+ | 날짜 | #{dateTimeValue} | +--------+------------------+
[GET:/sample/{intValue}.xls] 요청 일때 , 다음과 같은 Excel Sheet 를 리턴한다.
** Response Sheet +--------+------------------+ | 정수 | 1 | +--------+------------------+ | 문자 | a | +--------+------------------+ | 실수 | 1 | +--------+------------------+ | 날짜 | 2010-01-01 | +--------+------------------+
Section 1.3, “<springfield:modules>”의 Excel View 는 요청은 파일 다운로드 형태로 응답한다.
이때 다운로드되는 파일 이름을 변경하기 위해서,
DownloadBean
을 implements 한다.
@Springfield(toplevelMapping="/sample", methodLevelMapping={"*.xls"}) @Entity public class Sample implements DownloadBean{ @Id private Integer intValue; @XlsProperty("새이름") private String stringValue; @XlsIgnore private Float floatValue; private DateTime dateTimeValue; @Override public String getContentName(){ return "YourFileName"; } }
[GET:/sample/{intValue}.xls] 요청 일때 , "YourFileName.xls" 이름으로 Excel Sheet 를 리턴한다.
Section 1.3, “<springfield:modules>”은 basePackage 를 기준으로 "/**/navigation.xml" 을 자동 스캔한다. 다음 예시의 navigation_ko.xml 과 navigation_en.xml 파일이 basePackage 내에 어떤 위치라도 존재한다면 별도의 설정없이 이를 load 한다.
<navigation> <navigation path="/foo" name="회사" pattern="/foo/**" access="hasRole('ADMIN')" /> ... </navigation>
<navigation> <navigation path="/foo" name="yourcompany" pattern="/foo/**" access="hasRole('ADMIN')" /> ... </navigation>
Table 3.3. navigation element
Attribute | Desc |
---|---|
path | Menu Link. |
name | Menu Display Name. |
pattern | Spring-Security Request-matching |
access | Spring-Security Common built-in expressions |