ææ°ã®ãã«ãã·ã¹ãã ã䜿çšãããšããœãŒã¹ããã¢ããªã±ãŒã·ã§ã³ãã³ã³ãã€ã«ããã³å®è¡ããããã»ã¹ãå®å šã«èªååã§ããŸãã ã¿ãŒã²ãããã·ã³ã§ã¯ãJDKã®ã¿ãå¿ èŠã§ãããã³ã¬ã¯ã¿ãŒèªäœãå«ãä»ã®ãã¹ãŠããªã³ã¶ãã©ã€ã§ããŒããããŸãã ã¢ã»ã³ããªããã»ã¹ãæ£ããæ§ç¯ããããšãã°ãããŒã¿ããŒã¹ã®èµ·åãSQLã¹ã¯ãªããã®å®è¡ãJavaãJavascriptãCSSãã¡ã€ã«ã®ã³ã³ãã€ã«ããµãŒãã¬ããã³ã³ããã®èµ·åãªã©ã®2ã€ã®ã³ãã³ããååŸããã ãã§ãã ããã¯ãGradleãHSQLDBãLiquibaseãGoogleã¯ããŒãžã£ãŒã³ã³ãã€ã«ãããã³Grettyã䜿çšããŠå®è£ ãããŸãã èšäºã®è©³çŽ°ã
å 容
- ã¯ããã«
- ãããžã§ã¯ãã®æåã®ç«ã¡äžã
- ã¢ããªã±ãŒã·ã§ã³ãã¬ãŒã ã¯ãŒã¯ïŒSpring MVCïŒ
- ãµãŒããŒèšå®ã®æ§æïŒGrettyïŒ
- ãã®ã³ã°
- ããŒã¿ããŒã¹ã®èµ·åïŒHSQLïŒ
- ããŒãã«ã®äœæïŒliquibaseïŒ
- ããŒã¿ããŒã¹ã®å å¡«ïŒliquibaseïŒ
- ãŠãŒã¶ãŒèªèšŒïŒSpringã»ãã¥ãªãã£ïŒ
- ãã°ã€ã³ããŒãžãå€æŽãã
- JavaScriptã䜿çšãã
- CSSã䜿çšãã
- ORMïŒJPA /äŒæ¢ç¶æ ïŒ
- RESTãµãŒãã¹
ã¯ããã«
æè¿ãææãªGradleãã«ããŒã«å¯ŸåŠããããšããŠãç§ã¯äžå¿«ãªæ©èœãèŠã€ããŸããã å€ãã®äººããåã ã®ããšãã©ãã ãçŽ æŽããããç°¡åãã€è¿ éã«è¡ãããã«ã€ããŠæžããŠããŸãã ãã ããå šäœåãèªåã§åéããå¿ èŠããããŸãã äŸãšããŠå°ããªã¢ããªã±ãŒã·ã§ã³ã䜿çšããŠãGradleãããªã¢ã«ã®ãã®æ¬ ç¹ãæé€ããããšããŸãã ã¢ããªã±ãŒã·ã§ã³èªäœã§ã¯ãJava EEã®çŸåšé¢é£æ§ã®ããåºç€ãæ€èšããããšããŸãã
ã¢ããªã±ãŒã·ã§ã³ã®äœæãšå®è¡ãéå§ããåã«ãèŠä»¶ã決å®ããŸãã ãããã¯å°ãã-3ããŒãžïŒ1ã€ã®ã«ãŒãããã¹ãŠã«ã¢ã¯ã»ã¹å¯èœããã1ã€ã¯èš±å¯ãŠãŒã¶ãŒã®ã¿ã«ã¢ã¯ã»ã¹å¯èœã æåŸã®ãã°ã€ã³ããŒãžãæ°ãããŠãŒã¶ãŒãäœæããããã®ããŒãžã§ãã è€éã§æçœã§ã¯ãããŸããã å žåçãªãããã«ã¡ã¯ãäžçïŒã ãããããã®ãããªå°ããªäŸã§ããJava EEã®åšåãšå·šå€§ãã瀺ãã«ã¯ååã§ãã éåžžã®éçºã§ã¯ããããžã§ã¯ããå®è¡ããããã«å¿ èŠãªæ§æãã¡ã€ã«ã®æ°ã¯æãããèšå€§ã«ãªããŸãã
幞ããªããšã«ããã®åé¡ã¯éå§æã«ã®ã¿çºçããŸãã ãããŠããµãŒããŒèšèªãšããŠJavaãéžæããã ãã§ã¯ãããŸããã ãµãŒããŒã¢ããªã±ãŒã·ã§ã³èªäœã¯å®å šã«ã¯æ©èœããŸããã ããŒã¿ããŒã¹ãŸãã¯å°ãªããšã1ã€ã®ãµãŒãã¬ããã³ã³ãããªã©ã®å€éšãªãœãŒã¹ãå¿ èŠã§ãã ããŒã¿ããŒã¹ãäºåã«æºåããããŒãã«ãäœæããŠããŒã¿ãå ¥åããå¿ èŠããããŸãã åŸè ã¯ãå³å¯ãªã¹ããŒã ã®ãªãéãªã¬ãŒã·ã§ãã«ããŒã¿ããŒã¹ã䜿çšããå Žåã§ãå¿ èŠã§ãã
ãã®ã³ã°ããªã·ãŒã®èšå®ãããŒã¿ããŒã¹ã®æäœãJavaScriptããã³CSSåŠçã®èªååã ã¢ããªã±ãŒã·ã§ã³ã䜿çšããåã«èšå®ããå¿ èŠããããã®ããããããããŸãã ãã£ãŠã¿ãŸãã
䜿çšæžã¿ã®ã¢ããªã±ãŒã·ã§ã³ããã©ã°ã€ã³ãã©ã€ãã©ãª
- JDK / JREã¯ãJavaçšã®ä»®æ³ãã·ã³ã§ãã
- ã¢ã€ãã¢ã¯éçºç°å¢ã§ãã
- Gradle-ãã«ãã·ã¹ãã
- Spring-ã¢ããªã±ãŒã·ã§ã³ãã¬ãŒã ã¯ãŒã¯ãå®éã«ã¯Java EEã¢ããªã±ãŒã·ã§ã³ã®æšæºãã¬ãŒã ã¯ãŒã¯
- Hibernate -JPAå®è£
- hsqldb-ããŒã¿ããŒã¹
- Jetty-ãµãŒãã¬ããã³ã³ãããŒ
- Gretty-ã³ã³ããããã°ãã䟿å©ã«èµ·åããããã®Gradleãã©ã°ã€ã³
- Liquibaseã¯ãSQLã¹ã¯ãªãããæäœããããã®ã©ã€ãã©ãªã§ãã
- Gradle JSãã©ã°ã€ã³ -javasriptãã¡ã€ã«ã®ããŒãžãšå§çž®
- Gradle CSSãã©ã°ã€ã³ -CSSãã¡ã€ã«ã®ããŒãžãšå§çž®
ãªã¹ãã¯å€§ãããªããŸãããã¢ããªã±ãŒã·ã§ã³ãæ£åžžã«èµ·åããã³å€æŽããã«ã¯ãæåã®ã¢ã€ãã ãšã€ã³ã¿ãŒããããžã®ã¢ã¯ã»ã¹ã®ã¿ãå¿ èŠã§ãã ããã«ãéçºç°å¢ãé 眮ããããšããå§ãããŸãããååãšããŠãã³ã³ãœãŒã«ãä»ããŠã¢ã»ã³ããªãå®è¡ããããšã§éçºç°å¢ããªããããšãã§ããŸãã
ãããžã§ã¯ãã®æåã®ç«ã¡äžã
Gradleã䜿çšããæ°ãããããžã§ã¯ããäœæããŸãã äœæããããããžã§ã¯ãã®æ§é ã
ã芧ã®ãšãããæ°ãããããžã§ã¯ãã«ãå€ãã®ãã¡ã€ã«ãå«ãŸããŠããŸãã åŸæ¥ããããã¯2ã€ã®ã°ã«ãŒãã«åããããŠããŸãã ããŒãžã§ã³ç®¡çã·ã¹ãã ïŒVCSïŒã«ä¿åããå¿ èŠããããã®ãšä¿åããªããã®ããããŸãã
次ã®ãã¡ã€ã«ãVCSã«ä¿åããå¿ èŠããããŸãã
- build.gradle-ãããžã§ã¯ãã®ãã«ãæ¹æ³ã説æãããã¡ã€ã«ã
- settings.gradle-ãããžã§ã¯ãããã«ãããããã®äžè¬çãªèšå®ã
- srcãã©ã«ããŒ-ãœãŒã¹ã³ãŒããšãããžã§ã¯ããªãœãŒã¹ãå«ãŸããŠããŸãã
- LICENSE.txt-ãããžã§ã¯ããé åžãããã©ã€ã»ã³ã¹ïŒããã©ã«ãã§ã¯äœæãããŸããïŒã
- gradlewãgradlew.batãgradle-wrapper.jarãgradle-wrapper.propertiesã¯ãgradle-wrapperã®ãŠãŒãã£ãªãã£ãã¡ã€ã«ã§ãã Wrapperã¯gradleäžã®è»œéã·ã§ã«ã§ãããå¿
èŠã«å¿ããŠç¹å®ã®ïŒgradle-wrapper.propertiesã§æå®ãããïŒããŒãžã§ã³ã®ã³ã¬ã¯ã¿ãŒãããŠã³ããŒãããŸãã ãããã£ãŠããããžã§ã¯ãããã«ãããããã«gradleãäºåã«ã€ã³ã¹ããŒã«ããå¿
èŠã¯ãããŸããã
次ã®ãã¡ã€ã«ã¯ãããžã§ã¯ãã®äžéšã§ãããVCSã«ä¿åããªãã§ãã ããã
- gradle.properties-ããŒã«ã«gradleèšå®ãæã€ãã¡ã€ã«ïŒããã©ã«ãã§ã¯äœæãããŸããïŒã
- tit.iml-ã¢ã€ãã¢ãããžã§ã¯ããã¡ã€ã«
- ãµãŒãã¹ãã©ã«ããŒ.gradleãbuildãout
åããŒãžã§ã³ã·ã¹ãã ã«ã¯ãVCSã«ä¿åãããã©ã«ããŒ/ãã¡ã€ã«ãèšè¿°ããç¬èªã®ãã¡ã€ã«ããããŸãã ãã¹ãŠã®éçºè ã®éã§çµ±äžæ§ãç¶æãããããã«ãããèªäœãVCSã«ä¿åããå¿ èŠããããŸãã gitã䜿çšããå Žåã.gitignoreã®å 容ã¯ããã次ã®ãšããã§ãã
.gitignore
*.iml .idea/ /out/ /gradle.properties
æ°ãããããžã§ã¯ããéå§ããã«ã¯ããµãŒãã¬ããã³ã³ãããããŠã³ããŒãããŠå±éã§ããGradleçšã®Grettyãã©ã°ã€ã³ã䜿çšããŸãã ãã©ã°ã€ã³ã¯build.gradleãã¡ã€ã«ã§æ¥ç¶ãããŸãã
plugins { id "org.akhikhl.gretty" version "1.2.4" }
ãã©ã°ã€ã³ã䜿çšãããšããµãŒããŒã®ããŠã³ããŒããã€ã³ã¹ããŒã«ãããã³èµ·åã1ã€ã®ã³ãã³ãã«åæžãããŸãã
gradlew jettyStart
ãjettyStartããéžæããŠãIdeaããçŽæ¥èµ·åããããšãã§ããŸãã gradleã®ãžã§ããªã¹ãã ãã®ã³ãã³ãã§ã¯ãjettyããŒãžã§ã³9ãããŠã³ããŒããããèªåçã«å±éãããŸãã ãããžã§ã¯ãã¯localhostïŒ8080 / gull /ã§å©çšå¯èœã«ãªããŸãã ãµãŒããŒserverãåæ¢ããã«ã¯ããjettyStopãã䜿çšããŸãã
jettyRunã¯ãIdeaããèµ·åãããšæ£ããæ©èœããªãããã䜿çšããªãã§ãã ããïŒèµ·ååŸããã«çµäºããŸãïŒã
ãµãŒããŒããããã°ã¢ãŒãã§èµ·åããã«ã¯ããjettyStartDebugãã䜿çšããŸã
詳现
ãjettyStartDebugãã³ãã³ãã§èµ·åãããšããµãŒããŒã¯ãããã¬ãæ¥ç¶ããããŸã§åŸ
æ©ããŸãã Ideaã§ãããè¡ãã«ã¯ãã¡ãã¥ãŒrun-> Edit Configurationã䜿çšããŠæ°ããæ§æãäœæããå¿
èŠããããŸã
æ°ããããªã¢ãŒããæ§æãè¿œå ããŸãã ããã©ã«ãèšå®ã¯å€æŽããŸããã
ããã§ãæ°ããæ§æãéžæããŠãµãŒããŒã«åå ã§ããŸãã
æ°ããããªã¢ãŒããæ§æãè¿œå ããŸãã ããã©ã«ãèšå®ã¯å€æŽããŸããã
ããã§ãæ°ããæ§æãéžæããŠãµãŒããŒã«åå ã§ããŸãã
Spring MVC
ããã©ã«ãã§ã¯ããããžã§ã¯ãã¯1ã€ã®ãã«ãŒããããŒãžã®ã¿ã衚瀺ã§ããŸãã æ©èœãæ¡åŒµããã«ã¯ã model-view-controllerãã¿ãŒã³ãå®è£ ããSpring MVCã䜿çšããŸãã ç§ãã¡ã®å Žåããã¬ãŒã³ããŒã·ã§ã³ã¯JSPããŒãžã§ãããJavaã³ã³ãããŒã©ã¯ã©ã¹ãããŒã¿ã¢ãã«ãçæããŸãã
ã©ã€ãã©ãªãæ¥ç¶ããŸãã
build.gradleã
settings.gradle
dependencies { compile group: 'org.springframework', name: 'spring-webmvc', version: gradle.springVersion }
settings.gradle
gradle.ext.springVersion = '4.2.2.RELEASE'
spring-webmvcã©ã€ãã©ãªããããžã§ã¯ãã«æ¥ç¶ãããšãã©ã€ãã©ãªèªäœãäŸåããŠãããããSpringã«ãŒãã«ãæé»çã«è¿œå ãããŸãã å¿ èŠã«å¿ããŠã次ã®ã©ã€ãã©ãªãæå®ããŠã«ãŒãã«ãæ瀺çã«è¿œå ã§ããŸãã
- ã¹ããªã³ã°ã³ã¢
- æ¥è±
- æ¥ã®ã³ã³ããã¹ã
äŸåé¢ä¿ã®å®è£ ãéããŠãç°çš®ã®ã¯ã©ã¹ãšãã¡ã€ã«ãåäžã®ã¢ããªã±ãŒã·ã§ã³ã«åéããã®ã¯ãSpringã®ã³ã¢ã§ãããšèšããŸãã
Springã®ææ°ããŒãžã§ã³ã§ã¯ãæ§æå šäœãã³ãŒãã§çŽæ¥æå®ããããšãã§ããŸã ã ãã®ã¢ãããŒãã¯ç§ã«ãšã£ãŠéæ¿ãããããã§ããçµå±ã®ãšãããããŒã¿ããŒã¹ã«æ¥ç¶ããæ§æã¯ãã³ãŒãã§ã¯ãªãxmlãã¡ã€ã«ãšããŠããé©åã«èŠããŸãã ãããã£ãŠãXMLãä»ããéšåãã¢ãããŒã·ã§ã³ãä»ããéšåã®æ··åã¢ãããŒãã䜿çšããŸãã
ã¢ããªã±ãŒã·ã§ã³ããããã€ããæ¹æ³ã®èª¬æã¯web.xmlã«ä¿åãããŸãã 3ã€ã®èŠçŽ ãå«ãŸããŠããŸãã
- ãªã¹ããŒ-æ§æãã¡ã€ã«ã®è¡šç€ºïŒããã©ã«ãã®applicationContext.xmlïŒ
- ãµãŒãã¬ãã-ãªã¯ãšã¹ããåŠçããã¯ã©ã¹
- servlet-mapping-æå®ããããµãŒãã¬ãããæ
åœãããªã¯ãšã¹ããèšè¿°ããŸãã ããšãã°ãã/ããæå®ãããšãã¹ãŠã®èŠæ±ãã€ã³ã¿ãŒã»ãããããã/ admin /ããæå®ãããšãadminãã§ã®ã¿éå§ãããŸãã è€æ°ã®ãããã³ã°ã1ã€ã®ãã¹ãæãå Žåãæãæ£ç¢ºãªãããã³ã°ã䜿çšãããŸãã
web.xml
<ïŒxml version = "1.0" encoding = "UTF-8"ïŒ>
<web-app xmlnsïŒxsi = " www.w3.org/2001/XMLSchema-instance "ããŒãžã§ã³= "2.4"
xmlns = " java.sun.com/xml/ns/j2ee "
xsiïŒschemaLocation = " java.sun.com/xml/ns/j2ee java.sun.com/xml/ns/j2ee/web-app_2_4.xsd ">
<servlet-name>ãã£ã¹ãããã£ãŒ</ servlet-name>
<servlet-class> org.springframework.web.servlet.DispatcherServlet </ servlet-class>
<load-on-startup> 1 </ load-on-startup>
<servlet-mapping>
<servlet-name>ãã£ã¹ãããã£ãŒ</ servlet-name>
<url-pattern> / </ url-pattern>
</ servlet-mapping>
<listener-class> org.springframework.web.context.ContextLoaderListener </ listener-class>
</ web-app>
<web-app xmlnsïŒxsi = " www.w3.org/2001/XMLSchema-instance "ããŒãžã§ã³= "2.4"
xmlns = " java.sun.com/xml/ns/j2ee "
xsiïŒschemaLocation = " java.sun.com/xml/ns/j2ee java.sun.com/xml/ns/j2ee/web-app_2_4.xsd ">
<servlet-name>ãã£ã¹ãããã£ãŒ</ servlet-name>
<servlet-class> org.springframework.web.servlet.DispatcherServlet </ servlet-class>
<load-on-startup> 1 </ load-on-startup>
<servlet-mapping>
<servlet-name>ãã£ã¹ãããã£ãŒ</ servlet-name>
<url-pattern> / </ url-pattern>
</ servlet-mapping>
<listener-class> org.springframework.web.context.ContextLoaderListener </ listener-class>
</ web-app>
applicationContext.xml-ã¢ããªã±ãŒã·ã§ã³å šäœã«å ±éã®Beanã«ã€ããŠèª¬æããŸãã
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans>
dispatcher-servlet.xml-ç¹å®ã®ãµãŒãã¬ããã®Beanãå«ãŸããŸãã 泚ãµãŒãã¬ããã®ããã©ã«ãã®æ§æãã¡ã€ã«ã¯ãã-servlet.xmlããè¿œå ããããµãŒãã¬ãããšåãååã§ãã ãµãŒãã¬ããåã®éå±€ãç¶æããã«ã¯ãã/ãã䜿çšã§ããŸãã ããšãã°ããµãŒãã¬ãã ' admin / dispatcher 'ã¯ããã¡ã€ã« 'src / main / webapp / WEBINF / admin / dispatcher -servlet.xml'ã«å¯Ÿå¿ããŸãã
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- jsp view --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:view-controller path="/" view-name="index"/> <!-- mvc --> <mvc:annotation-driven/> <!-- --> <context:component-scan base-package="com.intetm.web"/> </beans>
dispatcher-servlet.xmlã§ã¯ããã¥ãŒã®JSPãã©ãã«ãããã瀺ãBeanãå®çŸ©ãããŠããŸãã ã«ãŒãïŒ "/"ïŒããŒãžãæå®ãããè¡<mvcïŒannotation-driven /> "Spring-mvcã¢ãããŒã·ã§ã³ãå«ããã§ãã¯ããã
Springã¯Controllerã¢ãããŒã·ã§ã³ã§ããŒã¯ããããã¹ãŠã®ã¯ã©ã¹ãæ€çŽ¢ãããã®äžã«@RequestMappingã¢ãããŒã·ã§ã³ãæã€ã¡ãœããããããŸãã ãã®ã¡ãœããã¯ãå ¥åãã©ã¡ãŒã¿ãŒãšããŠãããŒã¿ãå ¥åããå¿ èŠãããã¢ãã«ãåãå ¥ããŸãã ãã¥ãŒã®ååã¯ãåºåãã©ã¡ãŒã¿ãŒãšããŠæå®ãããŸãã 泚éãã©ã¡ãŒã¿ãŒå€ã¯ãåŠçäžã®ã¢ãã¬ã¹ã§ãã
package com.intetm.web.login; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class LoginController { private static final String HELLO_VIEW = "hello"; @RequestMapping(value = "/hello", method = RequestMethod.GET) public String hello(Model model) { model.addAttribute("subject", "world"); return HELLO_VIEW; } }
ãã¥ãŒå ã®ã¢ãã«å€æ°ãžã®ã¢ã¯ã»ã¹ã¯ãã$ {parametr_name}ãã®æ§ç¯ãéããŠè¡ãããŸãã hello.jspã§ã®äœ¿çšäŸã
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> Hello, ${subject}! </body> </html>
ããã©ã«ãããŒãžã§ããŠã§ã«ã«ã ããŒãžã§ãªã³ã¯ãæå®ããŸãã
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <a href="hello">Hello</a> </body> </html>
ãã¡ã€ã«ãè¿œå ããã³ç·šéããçµæã2ããŒãžã®ã¢ããªã±ãŒã·ã§ã³ãäœæãããŸãã ãããžã§ã¯ããéå§ããçµæã確èªããŸãã
ãµãŒããŒèšå®ãæ§æãã
ããã©ã«ãã®ãµãŒããŒèšå®ã¯ãåçŽãªã¢ããªã±ãŒã·ã§ã³ãèµ·åãããšãã«é©åãããããŸããããåŸã§å€æŽããå¿ èŠããããŸãã ããŒãããµãŒããŒã³ã³ããã¹ããæ§æããæ¹æ³ãèŠãŠã¿ãŸãããã ãã¡ã€ã«ãã¯ã©ã¹ãã¹ã«è¿œå ããŸãã
ããŒããæ§æããã«ã¯ãgrettyã«build.gradleã®é©åãªããŒãã䜿çšããããã«æ瀺ããŸãã
def serverHttpPort = project.properties['serverHttpPort'] ?: gradle.serverHttpPort gretty { httpPort = serverHttpPort }
ãããŠsettings.gradleã®ããã©ã«ãããŒã
//default config gradle.ext.serverHttpPort = 8080
ããã§ãå€æ° 'serverHttpPort'ãgradle.propertiesã§èŠã€ãã£ãå Žåãããã䜿çšãããŸãã ãã以å€ã®å Žåãsettings.gradleã®ããã©ã«ãå€ã䜿çšãããŸãã settings.gradleã¯gitã«ãããgradle.propertiesã¯é€å€ãããŠãããããäžæ¹ã§ãgitãšç«¶åããããšãªãããã©ã«ãå€ãéäžçã«æŽæ°ããå€ãããŒã«ã«ã«èšå®ã§ããŸãã
ãµãŒããŒã³ã³ããã¹ãã®å ŽåãVCSã«ããã©ã«ããã¡ã€ã«ãä¿åããããŒã«ã«ã§èªç±ã«å€æŽå¯èœãªã³ããŒãäœæããããšãæšå¥šãããŸãã serverContextFileå€æ°ãæå®ããŠãããŒã«ã«ã³ããŒãšå ±æã³ããŒãåãæ¿ããŸãã ããã©ã«ãã§ã¯ãVCSããã®ã³ããŒã䜿çšãããŸãã ããã«ããã¬ãŒãã³ã°ã®ããã«ãGradleã§ããŒã«ã«ã³ããŒãäœæããã¿ã¹ã¯ãå®è¡ããŸãã
build.gradleã
def serverResourcesPath = project.properties['serverResourcesPath'] ?: gradle.serverResourcesPath def serverContextFile = project.properties['serverContextFile'] ?: gradle.serverContextFile gretty { httpPort = serverHttpPort serverConfigFile = serverContextFile } task copyEnvironment(type: Copy) { from 'src/test/resources/environment' into serverResourcesPath }
ããã©ã«ãsettings.gradle
gradle.ext.serverResourcesPath = "dev/resources" gradle.ext.serverContextFile = "src/test/resources/environment/jetty-context.xml"
jettyã®ç©ºã®æ§æãã¡ã€ã«
src / test / resources / environment / jetty-context.xml
<?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd"> <Configure id="ExampleServer" class="org.eclipse.jetty.server.Server"> </Configure>
ãã¡ã€ã«ã®ã³ããŒãdev / resourcesãã©ã«ããŒã«äœæãããŸãã å°æ¥ãdevãã©ã«ããŒã¯ãã°ãšããŒã¿ããŒã¹ã®ä¿åã«ã䜿çšãããŸãã ã©ã³ãã ã³ããããé€å€ããã«ã¯ãVCSããdevãã©ã«ããŒå šäœãé€å€ããŸãã
åæ§ã«ããµãŒããŒã®ã¯ã©ã¹ãã¹ãæ§æã§ããŸãã ããšãã°ããã°èšå®ã§ãlogback.xmlããã¡ã€ã«ãè¿œå ããŸãã
build.gradleã
def serverClassPath = [project.properties['serverClassPath'] ?: gradle.serverClassPath] as Set gretty { ⊠classPath = serverClassPath }
settings.gradle
gradle.ext.serverClassPath = gradle.serverResourcesPath + "/classpath"
ãã®ã³ã°
Javaã§ã®ãã®ã³ã°ã·ã¹ãã ã®æŽå²ã¯ãããªãæ··ä¹±ããŠæ²ãããã®ã§ãã ãããžã§ã¯ãã¯ãslf4jãšlogbackã®å€ããå°ãªããé¢é£ããçµã¿åããã䜿çšããŸãã ãããè¡ãããã«ãbuild.gradleã«2ã€ã®äŸåé¢ä¿ãè¿œå ãããŸããã
dependencies { compile group: 'org.slf4j', name: 'slf4j-api', version: gradle.slf4jVersion runtime group: 'ch.qos.logback', name: 'logback-classic', version: gradle.logbackVersion ⊠}
settings.gradleã§äœ¿çšãããŠããããŒãžã§ã³
gradle.ext.slf4jVersion = '1.7.13' gradle.ext.logbackVersion = '1.1.3'
ãã°ããã¯ã«ã¯ããã°ã®æžã蟌ã¿æ¹æ³ãèšè¿°ããlogback.xmlãã¡ã€ã«ãå¿ èŠã§ãã å žåçãªèšå®ãã¡ã€ã«ã«ã¯ã次ã®ã³ã³ããŒãã³ããå«ãŸããŠããŸã
- ã¢ãã³ããŒ-ãã®ã³ã°çšã®ãã£ãã«ïŒã³ã³ãœãŒã«ããã¡ã€ã«ããŸãã¯ãã®ä»ïŒã ã¡ãã»ãŒãžã®èšé²åœ¢åŒããã¡ã€ã«ãã¹ããã¡ã€ã«ããŒããŒã·ã§ã³ããªã·ãŒãèšå®ããŸãã
- ã«ãŒã-æå®ããã¬ãã«ä»¥äžã®ãã¹ãŠã®ã¡ãã»ãŒãžãã€ã³ã¿ãŒã»ããããæå®ããã¢ãã³ããŒã«è»¢éããŸãã
- ãã¬ãŒ-ã«ãŒããšã¯ç°ãªããæå®ãããããã±ãŒãžã«å«ãŸããã¯ã©ã¹ããã®ã¡ãã»ãŒãžã®ã¿ãã€ã³ã¿ãŒã»ããããŸãã ïŒã¯ã©ã¹ã¯æšæºã®æ¹æ³ã§ã¡ãã»ãŒãžãèšé²ãããã¬ãŒåãšããŠå®å šãªã¯ã©ã¹åãæå®ãããšç解ãããŠããŸãïŒ
ãµã³ãã«logback.xmlãã¡ã€ã«
<!--suppress XmlUnboundNsPrefix --> <configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.padual.com/java/logback.xsd" scan="true" scanPeriod="10 seconds"> <!-- --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <!-- error. Debug, info . --> <level>ERROR</level> </filter> <encoder> <pattern> <!-- . , , ( ) --> %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{128} - %msg%n </pattern> </encoder> </appender> <!-- , --> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- --> <file>dev/logs/error.log</file> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <!-- error. Debug, info . --> <level>ERROR</level> </filter> <!-- . --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>dev/logs/old/%d{yyyy-MM-dd}.error.log</fileNamePattern> <maxHistory>7</maxHistory> </rollingPolicy> <encoder> <pattern> <!-- . , , ( ) --> %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{128} - %msg%n </pattern> </encoder> </appender> <!-- , --> <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- --> <file>dev/logs/debug.log</file> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>DEBUG</level> </filter> <!-- . --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>dev/logs/old/%d{yyyy-MM-dd}.debug.log</fileNamePattern> <maxHistory>7</maxHistory> </rollingPolicy> <encoder> <pattern> <!-- . , , ( ) --> %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{128} - %msg%n </pattern> </encoder> </appender> <!-- , --> <appender name="SQL_FILE" class="ch.qos.logback.core.FileAppender"> <!-- --> <file>dev/logs/sql.log</file> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>dev/logs/sql.lg</level> </filter> <!-- --> <append>false</append> <encoder> <pattern> <!-- . , , ( ) --> %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{128} - %msg%n </pattern> </encoder> </appender> <!-- , DEBUG , com.intetm DEBUG_FILE --> <logger name="com.intetm" level="DEBUG"> <appender-ref ref="DEBUG_FILE"/> </logger> <!-- hibernate--> <logger name="org.hibernate.type" level="ALL"> <appender-ref ref="SQL_FILE"/> </logger> <logger name="org.hibernate" level="DEBUG"> <appender-ref ref="SQL_FILE"/> </logger> <!-- ERROR_FILE--> <root level="ERROR"> <appender-ref ref="STDOUT"/> <appender-ref ref="ERROR_FILE"/> </root> </configuration>
LoginControllerã«ãã°ãèšé²ããè¡ãè¿œå ããŸãã
logger.debug("hello page");
å®å
šãªãã¡ã€ã«
package com.intetm.web.login; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class LoginController { private static final Logger logger = LoggerFactory.getLogger(LoginController.class); private static final String HELLO_VIEW = "hello"; @RequestMapping(value = "/hello", method = RequestMethod.GET) public String hello(Model model) { logger.debug("hello page"); model.addAttribute("subject", "world"); return HELLO_VIEW; } }
ãããžã§ã¯ããéå§ããŸãã localhost / gull / helloãå ¥åããããšãdev \ log \ debug.logãã¡ã€ã«ã«ãšã³ããªã衚瀺ãããããã«ããŸãã
ããŒã¿ããŒã¹ã®éå§
ãŠãŒã¶ãŒããã¹ã¯ãŒããããŒã«ã«é¢ããæ å ±ãä¿åããã«ã¯ãããŒã¿ããŒã¹ãå¿ èŠã§ãã ããŒã¿ããŒã¹ãã¢ããªã±ãŒã·ã§ã³èªäœã«çŽæ¥åã蟌ãããšã¯çè«çã«ã¯å¯èœã§ãããã¹ã±ãŒãªã³ã°ãæ¥ç¶ãå€éšãšãã£ã¿ãŒãªã©ã«åé¡ããããŸãã ãããã£ãŠãããŒã¿ããŒã¹ã¯ã¢ããªã±ãŒã·ã§ã³ã®å€éšã«ãããŸãã
Oracleããã³ãã®ä»ã®éãããŒã¿ããŒã¹ã«ã¯ãäºåã€ã³ã¹ããŒã«ãå¿ èŠã§ãã ããã¯ãã¹ã±ãŒã©ããªãã£ãšé©ç°çãªããã©ãŒãã³ã¹ã«å¯Ÿããæéã§ãã ãã®ãããªããŒã¿ããŒã¹ã¯ãæ°äžäººã®ãŠãŒã¶ãŒãæ±ããæŠéäœæŠã«é©ããŠããŸãã éçºäžããã®ãããªè² è·ã¯äºæ³ãããªããããå°ããªHSQLããŒã¿ããŒã¹ã䜿çšããŸãã
HSQLã¯ã€ã³ã¹ããŒã«ãå¿ èŠãšããŸãããjarãã¡ã€ã«ããçŽæ¥èµ·åãããããå°ããªã©ãããŒã䜿çšããŠGradleããçŽæ¥èµ·åãããŸãã æ®å¿µãªããããµãŒããŒã¢ãŒãã§GradleããHSQLãå®è¡ããæšæºçãªæ¹æ³ãèŠã€ãããªãã£ããããå°ããªèªè»¢è»ãäœæããŠå¥ã®ãã¡ã€ã«ã«å ¥ããŸããã
database.gradle
apply plugin: 'java' task startDatabase() { group = 'develop' outputs.upToDateWhen { return !available() } doLast { def dbUser = project.properties['dbUser'] ?: gradle.dbUser def dbPassword = project.properties['dbPassword'] ?: gradle.dbPassword def dbFile = project.properties['dbFile'] ?: gradle.dbFile def dbName = project.properties['dbName'] ?: gradle.dbName def className = "org.hsqldb.server.Server"; def filePath = "file:${projectDir}/${dbFile};user=${dbUser};password=${dbPassword}"; def process = buildProcess(className, filePath, dbName) wait(process) } } def buildProcess(className, filePath, dbName) { def javaHome = System.getProperty("java.home"); def javaBin = javaHome + File.separator + "bin" + File.separator + "java"; def classpath = project.buildscript.configurations.classpath.asPath; def builder = new ProcessBuilder(javaBin, "-cp", classpath, className, "-database.0", filePath, "-dbname.0", dbName); builder.redirectErrorStream(true) builder.directory(projectDir) def process = builder.start() process } def wait(Process process) { def ready = "From command line, use [Ctrl]+[C] to abort abruptly" def reader = new BufferedReader(new InputStreamReader(process.getInputStream())) def line; while ((line = reader.readLine()) != null) { logger.quiet line if (line.contains(ready)) { break; } } } import groovy.sql.Sql task stopDatabase() { group = 'develop' outputs.upToDateWhen { return available() } doLast { def dbUser = project.properties['dbUser'] ?: gradle.dbUser def dbPassword = project.properties['dbPassword'] ?: gradle.dbPassword def dbUrl = project.properties['dbUrl'] ?: gradle.dbUrl def dbDrive = project.properties['dbDrive'] ?: gradle.dbDrive ClassLoader loader = Sql.class.classLoader project.buildscript.configurations.classpath.each { File file -> loader.addURL(file.toURI().toURL()) } //noinspection GroovyAssignabilityCheck Sql sql = Sql.newInstance(dbUrl, dbUser, dbPassword, dbDrive) as Sql sql.execute('SHUTDOWN;') sql.close() } } boolean available() { try { int dbPort = project.properties['dbPort'] ?: gradle.dbPort as int String dbHost = project.properties['dbHost'] ?: gradle.dbHost Socket ignored = new Socket(dbHost, dbPort); ignored.close(); return false; } catch (IOException ignored) { return true; } }
build.gradleã§ã¯ããã¡ã€ã«ãã€ã³ã¯ã«ãŒãããhsqlã®äœ¿çšã瀺ãã ãã§æžã¿ãŸãã
buildscript { repositories { mavenLocal() mavenCentral() jcenter() } dependencies { classpath group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } } ⊠apply from: 'database.gradle'
settings.gradle
//lib version gradle.ext.hsqldbVersion = '2.3.2' //default database config gradle.ext.dbName = "xdb" gradle.ext.dbFile = "dev/database/devDB" gradle.ext.dbUser = "SA" gradle.ext.dbPassword = "password" gradle.ext.dbPort = 9001 gradle.ext.dbHost = "localhost" gradle.ext.dbUrl = "jdbc:hsqldb:hsql://${gradle.dbHost}:${gradle.dbPort}/${gradle.dbName}" gradle.ext.dbDrive = "org.hsqldb.jdbc.JDBCDriver"
ã³ã³ãœãŒã«ãŸãã¯Ideaã®Gradleã¿ã¹ã¯ã¡ãã¥ãŒããããŒã¿ããŒã¹ãèµ·åã§ããŸã
gradlew startDatabase
ã³ãã³ãã®å®è¡åŸãIdeaãå«ãå€éšãšãã£ã¿ãŒãä»ããŠããŒã¿ããŒã¹ã«æ¥ç¶ã§ããŸãã ããã©ã«ãã®ãŠãŒã¶ãŒ/ãã¹ã¯ãŒãã¯ãSAã/ãpasswordãã§ãã ã¢ãã¬ã¹ã¯jdbcïŒhsqldbïŒhsqlïŒ// localhostïŒ9001 / xdb
ããŒã¿ããŒã¹ã®ã·ã£ããããŠã³ãåæ§ã§ãã
gradlew stopDatabase
ããŒãã«äœæ
ã¢ããªã±ãŒã·ã§ã³ã§ãªã¬ãŒã·ã§ãã«ããŒã¿ããŒã¹ã®äœ¿çšãéå§ããåã«ãããŒãã«ãã€ã³ããã¯ã¹ãªã©ãäœæããå¿ èŠããããŸãã å³æ Œãªã¹ããŒã ããªãå Žåãéãªã¬ãŒã·ã§ãã«ããŒã¿ããŒã¹ã«ããŒã¿ãããã«æå ¥ã§ããŸãã ãã ããã©ã¡ãã®å ŽåãããŒã¿ã®å ¥åèªäœãè¡ãå¿ èŠããããŸãã
Liquibaseã¯ãSQLã¹ã¯ãªããã®å®è¡ãå¹çåããããã«äœ¿çšãããŸãã Liquibaseã¯æå®ãããé åºã§ã¹ã¯ãªãããå®è¡ã§ããåãã¹ã¯ãªããã2åå®è¡ãããªãããã«ããŸãã æ¢ã«å®è¡ãããã¹ã¯ãªãããå«ããã¡ã€ã«ãå€æŽããããšãå±éºãªç¶æ³ãèŠåããŸãã ç¹å®ã®ãã€ã³ããŸãã¯æéãžã®ããŒã«ããã¯ããµããŒãããŸãã Liquibaseã䜿çšãããšãè€æ°ã®ããŒã¿ããŒã¹ãæäœããéã®ãšã©ãŒã®æ°ãå€§å¹ ã«åæžãããŸãïŒæŠéããã¹ããªã©ïŒã
liquibaseãæ¥ç¶ãããã¡ã€ã«ãååŸããå Žæãã¿ã¹ã¯ãæµããäœæããå Žæãèšè¿°ããŸãã
build.gradle
plugins { id 'org.liquibase.gradle' version '1.1.1' } def dbUser = project.properties['dbUser'] ?: gradle.dbUser def dbPassword = project.properties['dbPassword'] ?: gradle.dbPassword def dbUrl = project.properties['dbUrl'] ?: gradle.dbUrl liquibase { activities { //noinspection GroovyAssignabilityCheck main { changeLogFile 'src/sql/main/changelog.xml' url dbUrl username dbUser password dbPassword } } } task updateDbMain(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main' tasks.update.execute() } }
å®å
šãªãã¡ã€ã«
buildscript { repositories { mavenLocal() mavenCentral() jcenter() } dependencies { classpath group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } } plugins { id "org.akhikhl.gretty" version "1.2.4" id 'org.liquibase.gradle' version '1.1.1' } group 'com.intetm' version '0.1' apply plugin: 'java' apply plugin: 'war' apply from: 'database.gradle' //noinspection GroovyUnusedAssignment sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile group: 'org.springframework', name: 'spring-webmvc', version: gradle.springVersion compile group: 'org.slf4j', name: 'slf4j-api', version: gradle.slf4jVersion runtime group: 'ch.qos.logback', name: 'logback-classic', version: gradle.logbackVersion } def serverHttpPort = project.properties['serverHttpPort'] ?: gradle.serverHttpPort def serverResourcesPath = project.properties['serverResourcesPath'] ?: gradle.serverResourcesPath def serverContextFile = project.properties['serverContextFile'] ?: gradle.serverContextFile def serverClassPath = [project.properties['serverClassPath'] ?: gradle.serverClassPath] as Set def dbUser = project.properties['dbUser'] ?: gradle.dbUser def dbPassword = project.properties['dbPassword'] ?: gradle.dbPassword def dbUrl = project.properties['dbUrl'] ?: gradle.dbUrl gretty { httpPort = serverHttpPort serverConfigFile = serverContextFile classPath = serverClassPath } task copyEnvironment(type: Copy) { group = 'develop' from 'src/test/resources/environment' into serverResourcesPath } liquibase { activities { //noinspection GroovyAssignabilityCheck main { changeLogFile 'src/sql/main/changelog.xml' url dbUrl username dbUser password dbPassword } } } task updateDbMain(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main' tasks.update.execute() } }
changelog.xmlãã¡ã€ã«ã«ã³ã³ãã³ããå ¥åããã ãã§ãã
èšäºã®ã¢ããã€ã¹ã«åŸã£ãŠã次ã®ã¹ã¯ãªããæ§é ã䜿çšãããŸãã
/src /sql /main /changelog.xml /v-1.0 /2015.11.28_01_Create_User_table.sql ... /changelog-v.1.0-cumulative.xml /v-2.0 ... /changelog-v.2.0-cumulative.xml
åããŒãžã§ã³ã®çŽ¯ç©ã¹ã¯ãªããã®ã¿ãã¡ã€ã³ã®changelog.xmlãã¡ã€ã«ã«å«ãŸããŠããŸãã
changelog.xml
<?xml version="1.0" encoding="UTF-8"?> <databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> <include file="src/sql/main/V-1.0/changelog-v.1.0-cumulative.xml"/> </databaseChangeLog>
Changelog-v.1.0-cumulative.xmlã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ããŒãžã§ã³1ã®ãã¹ãŠã®ã¹ã¯ãªãããå«ãŸããŠããŸãã
changelog-v.1.0-cumulative.xml
<?xml version="1.0" encoding="UTF-8"?> <databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> <changeSet id="Version 1 tag" author="Sivodedov Dmitry"> <tagDatabase tag="Version 1"/> </changeSet> <include file="src/sql/main/V-1.0/2015.11.28_01_Create_User_table.sql"/> </databaseChangeLog>
ç¹å®ã®å€æŽãªã¹ãã¯ãæäœã¬ãã«ã§ã®ã¿ä¿æãããŸãã
2015.11.28_01_Create_User_table.sql
--liquibase formatted sql --changeset Sivodedov Dmitry:CREATE_TABLE_Users CREATE TABLE Users ( id BINARY(16) NOT NULL PRIMARY KEY, username VARCHAR_IGNORECASE(50) NOT NULL, password VARCHAR(60) NOT NULL, enabled BOOLEAN NOT NULL ); --rollback drop table Users; --changeset Sivodedov Dmitry:CREATE_TRIGGER_TRIG_BI_DM_USERS splitStatements:false CREATE TRIGGER TRIG_BI_DM_USERS BEFORE INSERT ON Users REFERENCING NEW AS NEW FOR EACH ROW BEGIN ATOMIC IF NEW.id IS NULL THEN -- noinspection SqlResolve SET NEW.id = UUID(); END IF; END; --rollback drop TRIGGER TRIG_BI_DM_USERS on Users; --changeset Sivodedov Dmitry:CREATE_TABLE_Authorities CREATE TABLE Authorities ( id BIGINT IDENTITY NOT NULL PRIMARY KEY, userId BINARY(16) NOT NULL, authority VARCHAR_IGNORECASE(50) NOT NULL, CONSTRAINT fk_authorities_users FOREIGN KEY (userId) REFERENCES users (id) ); --rollback drop table Authorities; --changeset Sivodedov Dmitry:CREATE_INDEX_ix_auth_username CREATE UNIQUE INDEX ix_auth_username ON Authorities (userId, authority); --rollback drop INDEX ix_auth_username on Authorities;
ã¿ã¹ã¯ãupdateDbMainããéå§ãããšãå¿ èŠã«å¿ããŠããŒã¿ããŒã¹ãèªåçã«éå§ãããŸããçµæã¯2ã€ã®ããŒãã«ã«ãªããŸãã
ããŒã¿ããŒã¹ãæºãã
ããã«ãããŒã¿ããŒã¹ã§ã®ã¿éçºçšã®ã¹ã¯ãªãããå®è¡ããå¥ã®ã¿ã¹ã¯ãäœæããŸãã空ã®ããŒã¿ããŒã¹ã§ã®ãã¹ãã¯é£ãããSQLãä»ãããã¹ãããŒã¿ã®å ¥åã¯è³¢æãªæ¹æ³ãªã®ã§ãããã¯äŸ¿å©ã§ãã
build.gradleã®æ°ããã¿ã¹ã¯ãšãã®ãã©ã¡ãŒã¿ãŒ
liquibase { activities { ⊠dev { changeLogFile 'src/sql/dev/changelog.xml' url dbUrl username dbUser password dbPassword } } } task updateDbDev(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main, dev' tasks.update.execute() } }
å®å
šãªãã¡ã€ã«
buildscript { repositories { mavenLocal() mavenCentral() jcenter() } dependencies { classpath group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } } plugins { id "org.akhikhl.gretty" version "1.2.4" id 'org.liquibase.gradle' version '1.1.1' } group 'com.intetm' version '0.1' apply plugin: 'java' apply plugin: 'war' apply from: 'database.gradle' //noinspection GroovyUnusedAssignment sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile group: 'org.springframework', name: 'spring-webmvc', version: gradle.springVersion compile group: 'org.slf4j', name: 'slf4j-api', version: gradle.slf4jVersion runtime group: 'ch.qos.logback', name: 'logback-classic', version: gradle.logbackVersion } def serverHttpPort = project.properties['serverHttpPort'] ?: gradle.serverHttpPort def serverResourcesPath = project.properties['serverResourcesPath'] ?: gradle.serverResourcesPath def serverContextFile = project.properties['serverContextFile'] ?: gradle.serverContextFile def serverClassPath = [project.properties['serverClassPath'] ?: gradle.serverClassPath] as Set def dbUser = project.properties['dbUser'] ?: gradle.dbUser def dbPassword = project.properties['dbPassword'] ?: gradle.dbPassword def dbUrl = project.properties['dbUrl'] ?: gradle.dbUrl gretty { httpPort = serverHttpPort serverConfigFile = serverContextFile classPath = serverClassPath } task copyEnvironment(type: Copy) { group = 'develop' from 'src/test/resources/environment' into serverResourcesPath } liquibase { activities { //noinspection GroovyAssignabilityCheck main { changeLogFile 'src/sql/main/changelog.xml' url dbUrl username dbUser password dbPassword } dev { changeLogFile 'src/sql/dev/changelog.xml' url dbUrl username dbUser password dbPassword } } } task updateDbMain(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main' tasks.update.execute() } } task updateDbDev(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main, dev' tasks.update.execute() } }
ã¡ã€ã³ãªã¹ã
changelog.xml
src\sql\dev\changelog.xml
<?xml version="1.0" encoding="UTF-8"?> <databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> <include file="src/sql/dev/V-1.0/2015.11.28_01_Create_User.sql"/> </databaseChangeLog>
æåã®ããŒãžã§ã³ã®å€æŽã®ãªã¹ãã
changelog-v.1.0-cumulative.xml
src\sql\dev\V-1.0\changelog-v.1.0-cumulative.xml
<?xml version="1.0" encoding="UTF-8"?> <databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> <include file="src/sql/dev/V-1.0/2015.11.28_01_Create_User.sql"/> </databaseChangeLog>
ãŠãŒã¶ãŒã®çŽæ¥è¿œå ã
2015.11.28_01_Create_User.sql
sql\dev\V-1.0\2015.11.28_01_Create_User.sql
--liquibase formatted sql --changeset Sivodedov Dmitry:Create_User INSERT INTO USERS VALUES ('8a59d9547e5b4d9ca0a30804e8a33a94', 'admin', '$2a$10$GZtUdy1Z7Hpk0lYYG92CQeiW1f2c4e3XgA8wunVTDFyQJ2DAmH.x.', TRUE); INSERT INTO AUTHORITIES VALUES (1, '8a59d9547e5b4d9ca0a30804e8a33a94', 'ROLE_ADMIN'); INSERT INTO AUTHORITIES VALUES (2, '8a59d9547e5b4d9ca0a30804e8a33a94', 'ROLE_USER'); --rollback delete from AUTHORITIES where userId = '8a59d9547e5b4d9ca0a30804e8a33a94'; --rollback delete from USERS where id = '8a59d9547e5b4d9ca0a30804e8a33a94';
ãŠãŒã¶ãŒèªèšŒ
ããã§ãããŒã¿ããŒã¹ãèšå®ããŠå ¥åããåŸããŠãŒã¶ãŒãèªèšŒããããã®ããŒã¿ãœãŒã¹ãšããŠäœ¿çšã§ããŸããSpringã®ã³ã³ããŒãã³ãã®1ã€ã§ããSpring Securityã䜿çšããŸãã
Spring Securityãæ¥ç¶ãã
build.gradle
settings.gradle
dependencies { runtime group: 'org.springframework', name: 'spring-jdbc', version: gradle.springVersion runtime group: 'org.springframework.security', name: 'spring-security-web', version: gradle.springSecurityVersion runtime group: 'org.springframework.security', name: 'spring-security-config', version: gradle.springSecurityVersion // , gretty. // , classpath . gretty group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion }
buildscript { repositories { mavenLocal() mavenCentral() jcenter() } dependencies { classpath group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } } plugins { id "org.akhikhl.gretty" version "1.2.4" id 'org.liquibase.gradle' version '1.1.1' } group 'com.intetm' version '0.1' apply plugin: 'java' apply plugin: 'war' apply from: 'database.gradle' //noinspection GroovyUnusedAssignment sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { runtime group: 'org.springframework', name: 'spring-jdbc', version: gradle.springVersion compile group: 'org.springframework', name: 'spring-webmvc', version: gradle.springVersion runtime group: 'org.springframework.security', name: 'spring-security-web', version: gradle.springSecurityVersion runtime group: 'org.springframework.security', name: 'spring-security-config', version: gradle.springSecurityVersion compile group: 'org.slf4j', name: 'slf4j-api', version: gradle.slf4jVersion runtime group: 'ch.qos.logback', name: 'logback-classic', version: gradle.logbackVersion gretty group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } def serverHttpPort = project.properties['serverHttpPort'] ?: gradle.serverHttpPort def serverResourcesPath = project.properties['serverResourcesPath'] ?: gradle.serverResourcesPath def serverContextFile = project.properties['serverContextFile'] ?: gradle.serverContextFile def serverClassPath = [project.properties['serverClassPath'] ?: gradle.serverClassPath] as Set def dbUser = project.properties['dbUser'] ?: gradle.dbUser def dbPassword = project.properties['dbPassword'] ?: gradle.dbPassword def dbUrl = project.properties['dbUrl'] ?: gradle.dbUrl gretty { httpPort = serverHttpPort serverConfigFile = serverContextFile classPath = serverClassPath } task copyEnvironment(type: Copy) { group = 'develop' from 'src/test/resources/environment' into serverResourcesPath } liquibase { activities { //noinspection GroovyAssignabilityCheck main { changeLogFile 'src/sql/main/changelog.xml' url dbUrl username dbUser password dbPassword } dev { changeLogFile 'src/sql/dev/changelog.xml' url dbUrl username dbUser password dbPassword } } } task updateDbMain(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main' tasks.update.execute() } } task updateDbDev(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main, dev' tasks.update.execute() } }
settings.gradle
gradle.ext.springSecurityVersion = '4.0.2.RELEASE'
springã»ãã¥ãªãã£èšå®ãã¡ã€ã«ã§ãauthentication-managerãäœæããŸãããã¹ã¯ãŒãããã·ã¥ã«ã¯ãæ¯èŒç匷åãªBCryptã䜿çšãããŸããããŒã¿ããŒã¹ãžã®ã¢ã¯ã»ã¹ã¯ã次ã®ã³ã³ãã©ã¯ãã䜿çšããŠã2ã€ã®åçŽãªSQLã¯ãšãªãä»ããŠè¡ãããŸãã
- users-by-username-query-ãŠãŒã¶ãŒIDãæå®ãããšããŠãŒã¶ãŒãèŠã€ãã£ãå Žåã«1è¡ïŒååããã¹ã¯ãŒããããã¯ïŒã®ã¿ãè¿ããŸããããã§ãªããã°äœãã
- authority-by-username-query-æå®ããããŠãŒã¶ãŒIDã®ãã¢ã®ãªã¹ãïŒãŠãŒã¶ãŒåãããŒã«ïŒã
æš©éã®ãªããŠãŒã¶ãŒã«ã¯ããå¿åãã®åœ¹å²ããããŸãã
USERããŒã«ãæã€ãŠãŒã¶ãŒã®ã¿ãhelloããŒãžã«ã¢ã¯ã»ã¹ã§ããŸãã泚æïŒ ããŒã¿ããŒã¹ã§ã¯ããŠãŒã¶ãŒããŒã«ã¯ROLE_USERãšããŠèšè¿°ãããŠããŸãããæ§æã§ãUSERããæå®ãããŠããŸãã
security.xml
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd"> <http> <intercept-url pattern="/hello**" access="hasRole('USER')"/> <form-login default-target-url="/"/> <logout logout-url="/logout" logout-success-url="/"/> <anonymous username="guest" granted-authority="ANONYMOUS"/> <http-basic/> <remember-me/> </http> <authentication-manager> <authentication-provider> <password-encoder ref="encoder"/> <jdbc-user-service data-source-ref="dbDataSource" users-by-username-query="SELECT username, password, enabled FROM Users WHERE username= ?" authorities-by-username-query="SELECT u1.username, u2.authority FROM Users u1, Authorities u2 WHERE u1.id = u2.userId AND u1.UserName = ?"/> </authentication-provider> </authentication-manager> <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"> <beans:constructor-arg name="strength" value="10"/> </beans:bean> </beans:beans>
SpringãããŒã¿ããŒã¹ã«æ¥ç¶ã§ããããã«ããã«ã¯ãããã«ããã€ãã®æé ãå¿ èŠã§ãã
ããŒã¿ããŒã¹ã«ã¢ã¯ã»ã¹ããBeanãå®çŸ©ããŸãã
dbContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:jee="http://www.springframework.org/schema/jee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd"> <jee:jndi-lookup id="dbDataSource" jndi-name="jdbc/Database" expected-type="javax.sql.DataSource"/> </beans>
æ¥ã®ã»ãã¥ãªãã£èšå®ãšããŒã¿ããŒã¹èšå®ãå«ããã¡ã€ã«ãã¡ã€ã³ã¢ããªã±ãŒã·ã§ã³ã³ã³ããã¹ãã«æ¥ç¶ããŸãã
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <import resource="security.xml"/> <import resource="dbContext.xml"/> </beans>
ããŒã¿ããŒã¹ãžã®æ¥ç¶ãã¢ããªã±ãŒã·ã§ã³ããã³ã³ããã«è»¢éãããã£ã«ã¿ãŒãäœæããŸãããã£ã«ã¿ãŒã¯ããªã¯ãšã¹ãã察å¿ãããµãŒãã¬ããã«å°éããåã§ãã£ãŠãããã¹ãŠã®æ¥ç¶ãã€ã³ã¿ãŒã»ããããã»ãã¥ãªãã£èšå®ã«åŸã£ãŠããããåŠçããŸãã
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app.xsd"> <!--Security--> <!-- springSecurityFilterChain --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <!-- springSecurityFilterChain , /*--> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--Security--> <!--DispatcherServlet--> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--DispatcherServlet--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- --> <resource-ref> <!-- --> <description>Datasource</description> <!-- --> <res-ref-name>jdbc/Database</res-ref-name> <!-- --> <res-type>javax.sql.DataSource</res-type> <!-- , --> <res-auth>Container</res-auth> </resource-ref> </web-app>
ããŒã¿ããŒã¹èªäœãžã®ãªã³ã¯ããµãŒããŒã³ã³ããã¹ãã«è¿œå ããŸãã
jetty-context.xml
<?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd"> <Configure id="ExampleServer" class="org.eclipse.jetty.server.Server"> <New id="DS" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg> <Ref refid="wac"/> </Arg> <Arg>jdbc/Database</Arg> <Arg> <New class="org.hsqldb.jdbc.JDBCDataSource"> <Set name="DatabaseName">jdbc:hsqldb:hsql://localhost:9001/xdb</Set> <Set name="User">SA</Set> <Set name="Password">password</Set> </New> </Arg> </New> </Configure>
ããã§ãµãŒããŒãèµ·åããlocalhostããŒãž8080 / gull / helloã«ç§»åããŠãããŒãžã«å ¥ãåã«ãŠãŒã¶ãŒãšãã¹ã¯ãŒããå ¥åããå¿ èŠãããããšã確èªã§ããŸãããã®ãããªãŠãŒã¶ãŒïŒç®¡çè /ãã¹ã¯ãŒãïŒã¯ãæçµæ®µéã§äœæãããããŒã¿ããŒã¹ã«è¿œå ãããŸããã
ãã°ã€ã³ããŒãžãå€æŽãã
çŸåšããµãŒãããŒãã£ããŒã«ã«ãã£ãŠããŒã¿ããŒã¹ã«è¿œå ããããŠãŒã¶ãŒã®ã¿ãããŒãžã«ã¢ã¯ã»ã¹ã§ããŸããã¢ããªã±ãŒã·ã§ã³èªäœããçŽæ¥ãŠãŒã¶ãŒãäœæã§ããããã«ããŸããããç°¡çŽ åããã³å©äŸ¿æ§ã®ããã«ããã®æ©èœããã°ã€ã³ããŒãžã«çŽæ¥è¿œå ããŸãããã®ãããæåã«æšæºã®ãã°ã€ã³ããŒãžãç¬èªã®ãã°ã€ã³ããŒãžã«å€æŽããŸãã
security.xmlã§ãã°ã€ã³ããŒãžã䜿çšããããšãæå®ããŸãã
<form-login login-page="/login" default-target-url="/"/>
å®å
šãªãã¡ã€ã«
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd"> <http> <intercept-url pattern="/hello**" access="hasRole('USER')"/> <form-login login-page="/login" default-target-url="/"/> <logout logout-url="/logout" logout-success-url="/"/> <anonymous username="guest" granted-authority="ANONYMOUS"/> <http-basic/> <remember-me/> </http> <authentication-manager> <authentication-provider> <password-encoder ref="encoder"/> <jdbc-user-service data-source-ref="dbDataSource" users-by-username-query="SELECT username, password, enabled FROM Users WHERE username= ?" authorities-by-username-query="SELECT u1.username, u2.authority FROM Users u1, Authorities u2 WHERE u1.id = u2.userId AND u1.UserName = ?"/> </authentication-provider> </authentication-manager> <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"> <beans:constructor-arg name="strength" value="10"/> </beans:bean> </beans:beans>
dispatcher-servlet.xmlã§è¡šç€ºãããªã³ã¯ãè¿œå ããŸã
<mvc:view-controller path="/login" view-name="login"/>
å®å
šãªãã¡ã€ã«
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- jsp view --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:view-controller path="/" view-name="index"/> <mvc:view-controller path="/login" view-name="login"/> <!-- mvc --> <mvc:annotation-driven/> <!-- --> <context:component-scan base-package="com.intetm.web"/> </beans>
ãã°ã€ã³ããŒãžãäœæããŸãã
login.jsp
<%@ page contentType="text/html" pageEncoding="UTF-8" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!--suppress HtmlFormInputWithoutLabel --> <html> <head> <title>Login Page</title> </head> <body> <div align="center"> <h3>Login with Username and Password</h3> <form:form id='formLogin' action='./login' method='POST'> <table> <tr> <td>username:</td> <td><input type='text' name='username' value='' autofocus></td> </tr> <tr> <td>password:</td> <td><input type='password' name='password'/></td> </tr> <tr> <td><input type='checkbox' name='remember-me'/></td> <td>remember-me</td> </tr> <tr> <td colspan='2'><input name="submit" type="submit" value="submit"/></td> </tr> </table> </form:form> </div> </body> </html>
ãããŒããŒãžã«çµäºãªãã·ã§ã³ãè¿œå ããŸãã
hello.jsp
<%--suppress ELValidationInJSP --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Title</title> </head> <body> <!--suppress XmlPathReference --> <c:url value="/logout" var="logoutUrl"/> <!-- csrt support --> <form action="${logoutUrl}" method="post" id="logoutForm"> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> </form> <script> function formSubmit() { document.getElementById("logoutForm").submit(); } </script> <c:if test="${pageContext.request.userPrincipal.name != null}"> <h2> Welcome : ${pageContext.request.userPrincipal.name} | <a href="javascript:formSubmit()"> Logout</a> </h2> </c:if> Hello, ${subject}! </body> </html>
JSPã§æ¡ä»¶ã¹ããŒãã¡ã³ãã䜿çšããã«ã¯ãã©ã€ãã©ãªãè¿œå ã§æ¥ç¶ããå¿ èŠããããŸãã
ã©ã€ãã©ãªjstlãæ¥ç¶ããŸã
build.gradle
settings.gradle
dependencies { runtime group: 'org.apache.taglibs', name: 'taglibs-standard-impl', version: gradle.jstlVersion }
settings.gradle
gradle.ext.jstlVersion = '1.2.5'
å®è¡ããŠç¢ºèªããå¿ èŠããããŸãã
JavaScriptã䜿çšãã
JavaScriptããªããã°ãµã€ãã¯ã»ãšãã©ã§ããŸãããã¯ã©ã€ã¢ã³ãåŽã§ã³ãŒããå®è¡ãããšãããŒãžãå€æŽãããããªããŒãããã«å ¥åããŒã¿ãæ€èšŒãããããªã³ã¶ãã©ã€ã§ããŒãããããã¹ã¯ããããã¢ããªã±ãŒã·ã§ã³ã®æ¬æ Œçãªé¡äŒŒç©ãäœæãããã§ããŸãããããŠãããŠã³ããŒããé·ããªããªãããã«ãæé©åã®äžè©±ãããå¿ èŠããããŸãã
JavaScriptã2段éã§æé©åããŸãããŸããåæ£ãã¡ã€ã«ã1ã€ã«çµåããŸããããã«ããããµãã¯ãšãªã®æ°ãæžããããŠã³ããŒãé床ã«ãã©ã¹ã®å¹æããããŸãããã®åŸãåä¿¡ãããã¡ã€ã«ããäžèŠãªãã®ããã¹ãŠåé€ãããŸã-ã¹ããŒã¹ãã³ã¡ã³ããå€æ°åãççž®ãããŸãããã¡ãããæé©åã¯æåã§è¡ãããã®ã§ã¯ãªããã³ã³ãã€ã©ãŒã«ä»»ãããŸãã Gradleãã©ã°ã€ã³ã©ãããŒã§Google Closure Compilerã䜿çšããŸãã
泚æïŒã³ãŒããšæšæºã©ã€ãã©ãªãçµã¿åãããªãã§ãã ãããåŸè ã¯ãgooqleãµãŒããŒããæ¥ç¶ããæ¹ãé©åã§ããé«ã確çã§ããããã¯æ¢ã«ã¯ã©ã€ã¢ã³ãã®ãã£ãã·ã¥ã«ãããããŠã³ããŒãããå¿ èŠã¯ãããŸããã
ãã©ã°ã€ã³ãgradleã«æ¥ç¶ããŸãã
build.gradle
plugins { id "com.eriwen.gradle.js" version "1.12.1" }
çž®å°ãããã¡ã€ã«ãäœæããŸãã
login.js
$(function () { $("#tabs").tabs(); });
login.jspã«å€æŽãå ããŸããGoogleãµãŒããŒããjqueryã©ã€ãã©ãªã ãã§ãªããå°æ¥ã®çž®å°ãã¡ã€ã«ãæ¥ç¶ããŸãã
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="js/login.js"></script>
å®å
šãªãã¡ã€ã«
<%@ page contentType="text/html" pageEncoding="UTF-8" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!--suppress HtmlFormInputWithoutLabel --> <html> <head> <title>Login Page</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css"> <!--suppress HtmlUnknownTarget --> <script src="js/login.js"></script> </head> <body> <div align="center"> <div id="tabs"> <ul> <li><a href="#tabs-1">Sign in</a></li> <li><a href="#tabs-2">Create user</a></li> </ul> <div id="tabs-1"> <h3>Login with Username and Password</h3> <form:form id='formLogin' action='./login' method='POST'> <table> <tr> <td>username:</td> <td><input type='text' name='username' value='' autofocus></td> </tr> <tr> <td>password:</td> <td><input type='password' name='password'/></td> </tr> <tr> <td><input type='checkbox' name='remember-me'/></td> <td>remember-me</td> </tr> <tr> <td colspan='2'><input name="submit" type="submit" value="submit"/></td> </tr> </table> </form:form> </div> <div id="tabs-2"> <h3>Create user</h3> <form:form id='formCreate' action='./createUser' method='POST'> <table> <tr> <td>username:</td> <td><input type='text' name='username' value=''></td> </tr> <tr> <td>password:</td> <td><input type='password' name='password'/></td> </tr> <tr> <td colspan='2'><input name="submit" type="submit" value="submit"/></td> </tr> </table> </form:form> </div> </div> </div> </body> </html>
dispatcher-servlet.xmlã§ãå®æãããã¡ã€ã«ãä¿åããããã©ã«ããŒãæå®ããŸãã
<mvc:resources mapping="/js/**" location="/js/"/>
å®å
šãªãã¡ã€ã«
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- jsp view --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:view-controller path="/" view-name="index"/> <mvc:view-controller path="/login" view-name="login"/> <mvc:resources mapping="/js/**" location="/js/"/> <!-- mvc --> <mvc:annotation-driven/> <!-- --> <context:component-scan base-package="com.intetm.web"/> </beans>
javascriptãã¡ã€ã«ãåéããã³çž®å°ããbuild.gradleã¿ã¹ã¯ã«è¿œå ããããšã®ã¿ãæ®ããŸããGoogle Closure Compilerã¯ãœãŒã¹ãããã®äœææ¹æ³ãç¥ã£ãŠãããããçè«çã«ã¯çž®å°ããããã¡ã€ã«ãããã«æ¥ç¶ã§ããŸããå®éã«ã¯ããããã°äžã«å€æ°ã¯ççž®ããããããã°ãå°é£ã«ãªããŸãããããã£ãŠããããç°¡åã«ããŸã-éçºäžã¯çž®å°ããã«è¡ããæçµã¢ã»ã³ããªã«ã®ã¿æ¥ç¶ããŸãã
javascript.source { login { js { srcDir "src/main/js/login" include "*.js" } } } combineJs { source = javascript.source.login.js.files //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/js/combine/login.js") } minifyJs { source = combineJs //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/js/min/login.js") //sourceMap = file("${buildDir}/js/min/login.sourcemap.json") closure { warningLevel = 'QUIET' } } def dev = true; task copyJs(type: Copy) { group = 'develop' from(dev ? combineJs : minifyJs) as String into "src/main/webapp/js" } compileJava.dependsOn.add(copyJs)
å®å
šãªãã¡ã€ã«
buildscript { repositories { mavenLocal() mavenCentral() jcenter() } dependencies { classpath group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } } plugins { id "org.akhikhl.gretty" version "1.2.4" id 'org.liquibase.gradle' version '1.1.1' id "com.eriwen.gradle.js" version "1.12.1" } group 'com.intetm' version '0.1' apply plugin: 'java' apply plugin: 'war' apply from: 'database.gradle' //noinspection GroovyUnusedAssignment sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { runtime group: 'org.springframework', name: 'spring-jdbc', version: gradle.springVersion compile group: 'org.springframework', name: 'spring-webmvc', version: gradle.springVersion runtime group: 'org.springframework.security', name: 'spring-security-web', version: gradle.springSecurityVersion runtime group: 'org.springframework.security', name: 'spring-security-config', version: gradle.springSecurityVersion compile group: 'org.slf4j', name: 'slf4j-api', version: gradle.slf4jVersion runtime group: 'ch.qos.logback', name: 'logback-classic', version: gradle.logbackVersion runtime group: 'org.apache.taglibs', name: 'taglibs-standard-impl', version: gradle.jstlVersion gretty group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } def serverHttpPort = project.properties['serverHttpPort'] ?: gradle.serverHttpPort def serverResourcesPath = project.properties['serverResourcesPath'] ?: gradle.serverResourcesPath def serverContextFile = project.properties['serverContextFile'] ?: gradle.serverContextFile def serverClassPath = [project.properties['serverClassPath'] ?: gradle.serverClassPath] as Set def dbUser = project.properties['dbUser'] ?: gradle.dbUser def dbPassword = project.properties['dbPassword'] ?: gradle.dbPassword def dbUrl = project.properties['dbUrl'] ?: gradle.dbUrl gretty { httpPort = serverHttpPort serverConfigFile = serverContextFile classPath = serverClassPath inplaceMode = "hard" } task copyEnvironment(type: Copy) { group = 'develop' from 'src/test/resources/environment' into serverResourcesPath } liquibase { activities { //noinspection GroovyAssignabilityCheck main { changeLogFile 'src/sql/main/changelog.xml' url dbUrl username dbUser password dbPassword } dev { changeLogFile 'src/sql/dev/changelog.xml' url dbUrl username dbUser password dbPassword } } } task updateDbMain(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main' tasks.update.execute() } } task updateDbDev(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main, dev' tasks.update.execute() } } javascript.source { login { js { srcDir "src/main/js/login" include "*.js" } } } combineJs { source = javascript.source.login.js.files //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/js/combine/login.js") } minifyJs { source = combineJs //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/js/min/login.js") //sourceMap = file("${buildDir}/js/min/login.sourcemap.json") closure { warningLevel = 'QUIET' } } def dev = true; task copyJs(type: Copy) { group = 'develop' from(dev ? combineJs : minifyJs) as String into "src/main/webapp/js" } compileJava.dependsOn.add(copyJs)
ã芧ã®ãšãããcopyJsããã·ãŒãžã£ã¯ãã¢ãŒãã«å¿ããŠå§çž®ããŒãžã§ã³ãŸãã¯éå§çž®ããŒãžã§ã³ãæ¥ç¶ããŸããããã·ãŒãžã£ãæåã§åŒã³åºãå¿ èŠããªãããã«ãJavaãã¡ã€ã«ã®ã³ã³ãã€ã«ã«äŸåé¢ä¿ãè¿œå ããŸãããããã§ããã¹ãŠã®ãã¡ã€ã«ãåæã«ã³ã³ãã€ã«ãããŸãã
CSSã䜿çšãã
CSSã®æäœã¯JavaScriptãšå€ãããŸããããã¡ã€ã«ã1ã€ã®å§çž®ãã¡ã€ã«ã«ããŒãžãããŸãããã©ã°ã€ã³ãšé¢æ°ã®ååã¯ç°ãªããJavaScriptã®ä»£ããã«CSSæåã䜿çšãããŸãããã©ã°ã€ã³ãšã¿ã¹ã¯ãbuild.gradleã«è¿œå ããŸãã
plugins { id "com.eriwen.gradle.css" version "1.11.1" } css.source { login { css { srcDir "src/main/css/login" include "*.css" } } } combineCss { source = css.source.login.css.files //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/css/combine/login.css") } minifyCss { source = combineCss dest = file("${buildDir}/css/min/login.css") yuicompressor { // Optional lineBreakPos = -1 } } task copyCss(type: Copy) { group = 'develop' from(dev ? combineCss : minifyCss) as String into "src/main/webapp/css" } compileJava.dependsOn.add(copyCss)
å®å
šãªãã¡ã€ã«
buildscript { repositories { mavenLocal() mavenCentral() jcenter() } dependencies { classpath group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } } plugins { id "org.akhikhl.gretty" version "1.2.4" id 'org.liquibase.gradle' version '1.1.1' id "com.eriwen.gradle.js" version "1.12.1" id "com.eriwen.gradle.css" version "1.11.1" } group 'com.intetm' version '0.1' apply plugin: 'java' apply plugin: 'war' apply from: 'database.gradle' //noinspection GroovyUnusedAssignment sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { runtime group: 'org.springframework', name: 'spring-jdbc', version: gradle.springVersion compile group: 'org.springframework', name: 'spring-webmvc', version: gradle.springVersion runtime group: 'org.springframework.security', name: 'spring-security-web', version: gradle.springSecurityVersion runtime group: 'org.springframework.security', name: 'spring-security-config', version: gradle.springSecurityVersion compile group: 'org.slf4j', name: 'slf4j-api', version: gradle.slf4jVersion runtime group: 'ch.qos.logback', name: 'logback-classic', version: gradle.logbackVersion runtime group: 'org.apache.taglibs', name: 'taglibs-standard-impl', version: gradle.jstlVersion gretty group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } def serverHttpPort = project.properties['serverHttpPort'] ?: gradle.serverHttpPort def serverResourcesPath = project.properties['serverResourcesPath'] ?: gradle.serverResourcesPath def serverContextFile = project.properties['serverContextFile'] ?: gradle.serverContextFile def serverClassPath = [project.properties['serverClassPath'] ?: gradle.serverClassPath] as Set def dbUser = project.properties['dbUser'] ?: gradle.dbUser def dbPassword = project.properties['dbPassword'] ?: gradle.dbPassword def dbUrl = project.properties['dbUrl'] ?: gradle.dbUrl gretty { httpPort = serverHttpPort serverConfigFile = serverContextFile classPath = serverClassPath inplaceMode = "hard" } task copyEnvironment(type: Copy) { group = 'develop' from 'src/test/resources/environment' into serverResourcesPath } liquibase { activities { //noinspection GroovyAssignabilityCheck main { changeLogFile 'src/sql/main/changelog.xml' url dbUrl username dbUser password dbPassword } dev { changeLogFile 'src/sql/dev/changelog.xml' url dbUrl username dbUser password dbPassword } } } task updateDbMain(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main' tasks.update.execute() } } task updateDbDev(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main, dev' tasks.update.execute() } } javascript.source { login { js { srcDir "src/main/js/login" include "*.js" } } } combineJs { source = javascript.source.login.js.files //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/js/combine/login.js") } minifyJs { source = combineJs //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/js/min/login.js") //sourceMap = file("${buildDir}/js/min/login.sourcemap.json") closure { warningLevel = 'QUIET' } } css.source { login { css { srcDir "src/main/css/login" include "*.css" } } } combineCss { source = css.source.login.css.files //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/css/combine/login.css") } minifyCss { source = combineCss dest = file("${buildDir}/css/min/login.css") yuicompressor { // Optional lineBreakPos = -1 } } def dev = true; task copyJs(type: Copy) { group = 'develop' from(dev ? combineJs : minifyJs) as String into "src/main/webapp/js" } task copyCss(type: Copy) { group = 'develop' from(dev ? combineCss : minifyCss) as String into "src/main/webapp/css" } compileJava.dependsOn.add(copyJs) compileJava.dependsOn.add(copyCss)
login.cssãäœæããŸã
login.css
.tab-centered { width: 500px; } .tab-centered .ui-tabs-nav { height: 2.35em; text-align: center; } .tab-centered .ui-tabs-nav li { display: inline-block; float: none; margin: 0; }
ããŒãžã«CSSãè¿œå ããŸãã
<link rel="stylesheet" href="css/login.css"> ... <div id="tabs" class="tab-centered">
å®å
šãªãã¡ã€ã«
<%@ page contentType="text/html" pageEncoding="UTF-8" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!--suppress HtmlFormInputWithoutLabel --> <html> <head> <title>Login Page</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css"> <!--suppress HtmlUnknownTarget --> <script src="js/login.js"></script> <!--suppress HtmlUnknownTarget --> <link rel="stylesheet" href="css/login.css"> </head> <body> <div align="center"> <div id="tabs" class="tab-centered"> <ul> <li><a href="#tabs-1">Sign in</a></li> <li><a href="#tabs-2">Create user</a></li> </ul> <div id="tabs-1"> <h3>Login with Username and Password</h3> <form:form id='formLogin' action='./login' method='POST'> <table> <tr> <td>username:</td> <td><input type='text' name='username' value='' autofocus></td> </tr> <tr> <td>password:</td> <td><input type='password' name='password'/></td> </tr> <tr> <td><input type='checkbox' name='remember-me'/></td> <td>remember-me</td> </tr> <tr> <td colspan='2'><input name="submit" type="submit" value="submit"/></td> </tr> </table> </form:form> </div> <div id="tabs-2"> <h3>Create user</h3> <form:form id='formCreate' action='./createUser' method='POST'> <table> <tr> <td>username:</td> <td><input type='text' name='username' value=''></td> </tr> <tr> <td>password:</td> <td><input type='password' name='password'/></td> </tr> <tr> <td colspan='2'><input name="submit" type="submit" value="submit"/></td> </tr> </table> </form:form> </div> </div> </div> </body> </html>
cssãã¡ã€ã«ã®ååŸå ã§ããspring-mvcãæå®ããŸãã
<mvc:resources mapping="/css/**" location="/css/"/>
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- jsp view --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:view-controller path="/" view-name="index"/> <mvc:view-controller path="/login" view-name="login"/> <mvc:resources mapping="/js/**" location="/js/"/> <mvc:resources mapping="/css/**" location="/css/"/> <!-- mvc --> <mvc:annotation-driven/> <!-- --> <context:component-scan base-package="com.intetm.web"/> </beans>
ã³ã³ãã€ã«æã«ãJavaãã¡ã€ã«ãšJavaScriptãã¡ã€ã«ãCSSãã¡ã€ã«ã®äž¡æ¹ãåæã«ã³ã³ãã€ã«ãããããã«ãªããŸãããçµæã¯localhostããŒãžã§å©çšå¯èœã§ãïŒ8080 / gull / login
ORM
ã¬ã¹ããµãŒãã¹ãäœæããåã«ãORMã®åœ¢åŒã§ããŒã¿ããŒã¹ãæäœãããšãã«ã¬ã€ã€ãŒãè¿œå ããŸããç¹å®ã®ORMå®è£ ã«äŸåããªãããã«ãjavaee-apiã©ã€ãã©ãªã®äžéšã§ããå ±éã®JPAã€ã³ã¿ãŒãã§ãŒã¹ã䜿çšããŸããç¹å®ã®å®è£ ïŒäŒæ¢ç¶æ ïŒã¯ãèµ·åæã«ã®ã¿æ¥ç¶ããŸãã
build.gradle
compile group: 'javax', name: 'javaee-api', version: gradle.javaxVersion compile group: 'org.springframework', name: 'spring-orm', version: gradle.springVersion compile group: 'org.springframework', name: 'spring-tx', version: gradle.springVersion runtime group: 'org.hibernate.javax.persistence', name: 'hibernate-jpa-2.1-api', version: gradle.hibernateJpaVersion runtime group: 'org.hibernate', name: 'hibernate-core', version: gradle.hibernateVersion runtime group: 'org.hibernate', name: 'hibernate-entitymanager', version: gradle.hibernateVersion
å®å
šãªãã¡ã€ã«
buildscript { repositories { mavenLocal() mavenCentral() jcenter() } dependencies { classpath group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } } plugins { id "org.akhikhl.gretty" version "1.2.4" id 'org.liquibase.gradle' version '1.1.1' id "com.eriwen.gradle.js" version "1.12.1" id "com.eriwen.gradle.css" version "1.11.1" } group 'com.intetm' version '0.1' apply plugin: 'java' apply plugin: 'war' apply from: 'database.gradle' //noinspection GroovyUnusedAssignment sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile group: 'javax', name: 'javaee-api', version: gradle.javaxVersion runtime group: 'org.springframework', name: 'spring-jdbc', version: gradle.springVersion compile group: 'org.springframework', name: 'spring-webmvc', version: gradle.springVersion compile group: 'org.springframework', name: 'spring-orm', version: gradle.springVersion compile group: 'org.springframework', name: 'spring-tx', version: gradle.springVersion runtime group: 'org.springframework.security', name: 'spring-security-web', version: gradle.springSecurityVersion runtime group: 'org.springframework.security', name: 'spring-security-config', version: gradle.springSecurityVersion runtime group: 'org.hibernate.javax.persistence', name: 'hibernate-jpa-2.1-api', version: gradle.hibernateJpaVersion runtime group: 'org.hibernate', name: 'hibernate-core', version: gradle.hibernateVersion runtime group: 'org.hibernate', name: 'hibernate-entitymanager', version: gradle.hibernateVersion compile group: 'org.slf4j', name: 'slf4j-api', version: gradle.slf4jVersion runtime group: 'ch.qos.logback', name: 'logback-classic', version: gradle.logbackVersion runtime group: 'org.apache.taglibs', name: 'taglibs-standard-impl', version: gradle.jstlVersion gretty group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } def serverHttpPort = project.properties['serverHttpPort'] ?: gradle.serverHttpPort def serverResourcesPath = project.properties['serverResourcesPath'] ?: gradle.serverResourcesPath def serverContextFile = project.properties['serverContextFile'] ?: gradle.serverContextFile def serverClassPath = [project.properties['serverClassPath'] ?: gradle.serverClassPath] as Set def dbUser = project.properties['dbUser'] ?: gradle.dbUser def dbPassword = project.properties['dbPassword'] ?: gradle.dbPassword def dbUrl = project.properties['dbUrl'] ?: gradle.dbUrl gretty { httpPort = serverHttpPort serverConfigFile = serverContextFile classPath = serverClassPath inplaceMode = "hard" } task copyEnvironment(type: Copy) { group = 'develop' from 'src/test/resources/environment' into serverResourcesPath } liquibase { activities { //noinspection GroovyAssignabilityCheck main { changeLogFile 'src/sql/main/changelog.xml' url dbUrl username dbUser password dbPassword } dev { changeLogFile 'src/sql/dev/changelog.xml' url dbUrl username dbUser password dbPassword } } } task updateDbMain(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main' tasks.update.execute() } } task updateDbDev(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main, dev' tasks.update.execute() } } javascript.source { login { js { srcDir "src/main/js/login" include "*.js" } } } combineJs { source = javascript.source.login.js.files //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/js/combine/login.js") } minifyJs { source = combineJs //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/js/min/login.js") //sourceMap = file("${buildDir}/js/min/login.sourcemap.json") closure { warningLevel = 'QUIET' } } css.source { login { css { srcDir "src/main/css/login" include "*.css" } } } combineCss { source = css.source.login.css.files //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/css/combine/login.css") } minifyCss { source = combineCss dest = file("${buildDir}/css/min/login.css") yuicompressor { // Optional lineBreakPos = -1 } } def dev = true; task copyJs(type: Copy) { group = 'develop' from(dev ? combineJs : minifyJs) as String into "src/main/webapp/js" } task copyCss(type: Copy) { group = 'develop' from(dev ? combineCss : minifyCss) as String into "src/main/webapp/css" } compileJava.dependsOn.add(copyJs) compileJava.dependsOn.add(copyCss)
settings.gradleã
gradle.ext.javaxVersion = '7.0' gradle.ext.hibernateVersion = '5.0.2.Final' gradle.ext.hibernateJpaVersion = '1.0.0.Final'
å®å
šãªãã¡ã€ã«
rootProject.name = 'gull' //lib version gradle.ext.springVersion = '4.2.2.RELEASE' gradle.ext.springSecurityVersion = '4.0.2.RELEASE' gradle.ext.javaxVersion = '7.0' gradle.ext.hibernateVersion = '5.0.2.Final' gradle.ext.hibernateJpaVersion = '1.0.0.Final' gradle.ext.slf4jVersion = '1.7.13' gradle.ext.logbackVersion = '1.1.3' gradle.ext.hsqldbVersion = '2.3.2' gradle.ext.jstlVersion = '1.2.5' //default server config gradle.ext.serverHttpPort = 8080 gradle.ext.serverResourcesPath = "dev/resources" gradle.ext.serverContextFile = "src/test/resources/environment/jetty-context.xml" gradle.ext.serverClassPath = "src/test/resources/environment/classpath" //default database config gradle.ext.dbName = "xdb" gradle.ext.dbFile = "dev/database/devDB" gradle.ext.dbUser = "SA" gradle.ext.dbPassword = "password" gradle.ext.dbPort = 9001 gradle.ext.dbHost = "localhost" gradle.ext.dbUrl = "jdbc:hsqldb:hsql://${gradle.dbHost}:${gradle.dbPort}/${gradle.dbName}" gradle.ext.dbDrive = "org.hsqldb.jdbc.JDBCDriver"
JPAã§ã¯ã2ã€ã®Beanãäœæããå¿ èŠããããŸãã
- EntityManagerFactory-ã¡ã€ã³Beanã¯ãããŒã¿ããŒã¹ãORMãããã³ã³ãŒãéã®ããªããžãšããŠæ©èœããŸãã
- TransactionManager-ãã©ã³ã¶ã¯ã·ã§ã³ã管çããŸãã
dbContext.xml
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceXmlLocation" value="classpath:persistence.xml"/> <property name="persistenceUnitName" value="defaultUnit"/> <property name="dataSource" ref="dbDataSource"/> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> <property name="jpaDialect" ref="jpaDialect"/> </bean> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> <bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <context:component-scan base-package="com.intetm.db.dao"/>
å®å
šãªãã¡ã€ã«
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:jee="http://www.springframework.org/schema/jee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <jee:jndi-lookup id="dbDataSource" jndi-name="jdbc/Database" expected-type="javax.sql.DataSource"/> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceXmlLocation" value="classpath:persistence.xml"/> <property name="persistenceUnitName" value="defaultUnit"/> <property name="dataSource" ref="dbDataSource"/> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> <property name="jpaDialect" ref="jpaDialect"/> </bean> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> <bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <context:component-scan base-package="com.intetm.db.dao"/> </beans>
ãã§ã«äŒæ¢ç¶æ ã«ãªã£ãŠãããããèšå®ãã¡ã€ã«persistence.xmlãäœæããå¿ èŠããããŸãããã®ã³ã°ããªã·ãŒãããŒã¿ããŒã¹ã®ã¿ã€ããããŒã¿ããŒã¹æ§é ãæŽæ°ããããã®ããªã·ãŒãããã³ãã®ä»ã®ãµãŒããŒåºæã®ããŒã¿ãå«ãŸããŠããŸãããããžã§ã¯ããããã¡ã€ã«ãåãåºãããµãŒããŒã®classPathã«ã®ã¿æ¥ç¶ããŸãã
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence.xsd" version="2.1"> <persistence-unit name="defaultUnit" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <jta-data-source>jdbc/Database</jta-data-source> <class>com.intetm.db.entity.User</class> <!-- Hibernate properties --> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/> <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/> <property name="hibernate.connection.charSet" value="UTF-8"/> <property name="hibernate.validator.apply_to_ddl" value="false"/> <property name="hibernate.validator.autoregister_listeners" value="false"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.hbm2ddl.auto" value="validate"/> </properties> </persistence-unit> </persistence>
ãhibernate.hbm2ddl.autoããã©ã¡ãŒã¿ãŒã§ãvalidateãã§ã¯ãªããupdateããæå®ãããšãhibernateã¯æ¬ èœããŠããåãšããŒãã«ãè¿œå ããããšã«æ³šæããŠãã ãããããã¯ãSQLã¹ã¯ãªãããèšè¿°ãããããç°¡åãªæ¹æ³ã®ããã§ãããå°ãªããšã2ã€ã®äºå®ãèæ ®ããå¿ èŠããããŸãa
ïŒhibernateã¯éç Žå£çãªããŒã¿ããŒã¹å€æŽã®ã¿ãè¡ããŸããã€ãŸããããŒãã«ã®åã¯åé€ãããŸããã
bïŒãã¹ãŠã®ããŒã¿ç§»è¡ã¯ããµãŒãããŒãã£ã®ã¡ã«ããºã ã«ãã£ãŠè¡ãããå¿ èŠããããŸãã
ãããžã§ã¯ããæé·ããã«ã€ããŠããããã®å¶çŽã«ééããå¯èœæ§ã¯æ¥éã«å¢å ããŸãã
ã©ãããŒãšDAOãäœæããããã ãã«æ®ããŸãã泚éã«ãã£ãŠç€ºããããã®ã
User.java-ããŒãã«ã®ã©ãããŒãã¯ã©ã¹èªäœã«ã¯Entity泚éãä»ããŠããŸããããŒãã«ã®ååã¯ã«ãã£ãŠç€ºãããè¡šãã¯ã©ã¹ã«ã¯ããã©ã¡ãŒã¿ãŒã®ãªãã³ã³ã¹ãã©ã¯ã¿ãŒãå¿ èŠã§ãã
@Entity @Table(name = User.TABLE) public class User { ⊠}
ããŒãã«ã®åã«è¡šç€ºãããã¯ã©ã¹ã®ãã£ãŒã«ãã«ã¯ãååã®ä»ãã@Columnã¢ãããŒã·ã§ã³ãä»ããŠããŸãããããã®ãã£ãŒã«ãã«ã¯ãæšæºã®getããã³setã¡ãœãããååšããå¿ èŠããããŸãã
@Column(name = COLUMN_USER_NAME) private String userName;
User.java
package com.intetm.db.entity; import javax.persistence.*; import java.util.ArrayList; import java.util.List; import java.util.UUID; @Entity @Table(name = User.TABLE) public class User { public static final String TABLE = "Users"; public static final String COLUMN_ID = "id"; public static final String COLUMN_USER_NAME = "userName"; public static final String COLUMN_PASSWORD = "password"; public static final String COLUMN_ENABLED = "enabled"; @Id @Column(name = COLUMN_ID, columnDefinition = "BINARY(16)") private UUID id; @Column(name = COLUMN_USER_NAME) private String userName; @Column(name = COLUMN_PASSWORD) private String password; @Column(name = COLUMN_ENABLED) private boolean enabled; @ElementCollection(targetClass = Authority.class) @Enumerated(EnumType.STRING) @CollectionTable(name = Authority.TABLE, joinColumns = @JoinColumn(name = Authority.COLUMN_USERID, referencedColumnName = COLUMN_ID)) @Column(name = Authority.COLUMN_AUTHORITY) private List<Authority> authorities; public User() { } public User(String userName, String password, Authority authority) { this.userName = userName; this.password = password; this.enabled = true; this.authorities = new ArrayList<>(); this.authorities.add(authority); } public UUID getId() { return id; } public void setId(UUID id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public List<Authority> getAuthorities() { return authorities; } public void setAuthorities(List<Authority> authorities) { this.authorities = authorities; } }
Authority.java-泚éã®ãªãåçŽãªåæåãããŒãã«ãžã®ãªã³ã¯ã瀺ããã¹ãŠã®æ³šéã¯ãUser.javaã§æå®ãããŸãããã®ã¯ã©ã¹ã§ã¯ãããŒãã«ãšåã®ååã®ã¿ãã¬ã³ããªã³ã°ãããŸãã
Authority.java
package com.intetm.db.entity; public enum Authority { ROLE_ADMIN, ROLE_USER, ROLE_ANONYMOUS; public static final String TABLE = "authorities"; public static final String COLUMN_USERID = "userid"; public static final String COLUMN_AUTHORITY = "authority"; }
AbstractDaoã¯ããã¹ãŠã®Taoã®äžè¬åãããç¥å ã§ãã@PersistenceContextãš@PersistenceUnitã®2ã€ã®æ³šéãå«ãŸããŠããŸããããã«ãããSpringã¯entityManagerãšentityManagerFactoryã眮æããå Žæã決å®ããŸããããŒã¿ããŒã¹å ã®ãªããžã§ã¯ããããŒããä¿åãæ€çŽ¢ããäžè¬çãªæ¹æ³ããããŸãã
@PersistenceContext private EntityManager entityManager; @PersistenceUnit private EntityManagerFactory entityManagerFactory;
AbstractDao.java
package com.intetm.db.dao; import javax.persistence.*; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Path; import javax.persistence.criteria.Root; import java.util.List; import java.util.Map; public abstract class AbstractDao<Entity, ID> { private final Class entryClass; @PersistenceContext private EntityManager entityManager; @PersistenceUnit private EntityManagerFactory entityManagerFactory; public AbstractDao(Class entryClass) { this.entryClass = entryClass; } public void persist(Entity entity) { entityManager.persist(entity); } public void merge(Entity entity) { entityManager.merge(entity); } public void delete(Entity entity) { entityManager.remove(entity); } @SuppressWarnings("unchecked") public CriteriaQuery<Entity> createCriteriaQuery() { return this.getCriteriaBuilder().createQuery(entryClass); } @SuppressWarnings("unchecked") public Entity find(ID id) { return (Entity) entityManager.find(entryClass, id); } public List<Entity> find(CriteriaQuery<Entity> criteriaQuery) { TypedQuery<Entity> query = entityManager.createQuery(criteriaQuery); return query.getResultList(); } public List<Entity> find(Object... keysAndValues) { CriteriaBuilder criteriaBuilder = this.getCriteriaBuilder(); CriteriaQuery<Entity> criteriaQuery = this.createCriteriaQuery(); Root root = criteriaQuery.from(entryClass); fillQuery(criteriaQuery, keysAndValues, root, criteriaBuilder); return find(criteriaQuery); } public List<Entity> find(Map<String, Object> parameters) { Object[] array = toArray(parameters); return find(array); } @SuppressWarnings("unchecked") public long count(Object... keysAndValues) { CriteriaBuilder criteriaBuilder = this.getCriteriaBuilder(); CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class); Root<Entity> root = criteriaQuery.from(entryClass); criteriaQuery.select(criteriaBuilder.count(root)); fillQuery(criteriaQuery, keysAndValues, root, criteriaBuilder); return getEntityManager().createQuery(criteriaQuery).getSingleResult(); } public long count(Map<String, Object> parameters) { Object[] array = toArray(parameters); return count(array); } private void fillQuery(CriteriaQuery criteriaQuery, Object[] keysAndValues, Root root, CriteriaBuilder criteriaBuilder) { if (keysAndValues.length % 2 != 0) { throw new IllegalArgumentException("Expected even count argument, receive odd"); } for (int i = 0; i < keysAndValues.length; i += 2) { Path parameterPath = root.get((String) keysAndValues[i]); Object parameterValue = keysAndValues[i + 1]; criteriaQuery.where(criteriaBuilder.equal(parameterPath, parameterValue)); } } private Object[] toArray(Map<String, Object> parameters) { Object[] array = new Object[parameters.size() * 2]; int i = 0; for (Map.Entry<String, Object> parameter : parameters.entrySet()) { array[i] = parameter.getKey(); i++; array[i] = parameter.getValue(); i++; } return array; } public List<Entity> selectAll() { CriteriaQuery<Entity> criteriaQuery = createCriteriaQuery(); criteriaQuery.from(entryClass); return find(criteriaQuery); } public EntityManager getEntityManager() { return entityManager; } public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } public Object getEntityManagerFactory() { return entityManagerFactory; } public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) { this.entityManagerFactory = entityManagerFactory; } public CriteriaBuilder getCriteriaBuilder() { return this.entityManager.getCriteriaBuilder(); } }
UserDaoã¯ãUserããŒãã«ã®ç¹å®ã®Daoå®è£ ã§ãã@ Repositoryã¢ãããŒã·ã§ã³ã§ããŒã¯ãããSpringãç¹å¥ãªBeanã®å¿ èŠæ§ã瀺ããŠããããšã瀺ããŸããSpringã¯ãã¢ãããŒã·ã§ã³@PersistenceContextããã³@PersistenceUnitãæã€ã¯ã©ã¹ã®ãã£ãŒã«ããæ¢ããAbstractDaoåºæ¬ã¯ã©ã¹ã§ããããèŠã€ããŠå ¥åããŸãã
@Repository("userDao") public class UserDao extends AbstractDao<User, UUID>
UserDao.java
package com.intetm.db.dao; import com.intetm.db.entity.User; import org.springframework.stereotype.Repository; import java.util.UUID; @Repository("userDao") public class UserDao extends AbstractDao<User, UUID> { public UserDao() { super(User.class); } @Override public void persist(User user) { if (user.getId() == null) { user.setId(UUID.randomUUID()); } super.persist(user); } public boolean isUserExsist(String userName) { return count(User.COLUMN_USER_NAME, userName) != 0; } }
RESTãµãŒãã¹
ã¬ã¹ããµãŒãã¹ã¯ãã¢ããªã±ãŒã·ã§ã³ãžã®å ¥ãå£ãšåºå£ã§ããããã®çµæã¯ãã¹ãŠç°ãªããŸããå ¥åããŒã¿ã¹ããªãŒã ã¯ã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠå¶åŸ¡ãããªããããæããã«äžæ£ãªããŒã¿ãå«ãŸããŠããå¯èœæ§ããããŸããããã«ããããµãŒãã¹ã«è¿œå ã®ãšã©ãŒåŠçèŠä»¶ã課ãããŸãããªã¯ãšã¹ãã®åŠçäžã«ãšã©ãŒãçºçããå ŽåãããŒã¿ããŒã¹ãå¶åŸ¡äžèœã«å€æŽããŠãã¯ã©ã€ã¢ã³ãã®ã¹ã¿ãã¯ãã¬ãŒã¹ã«æž¡ããªãã§ãã ããããšã©ãŒãçºçããå Žåã®æ£ããåäœã¯ãé©çšããããã¹ãŠã®å€æŽã®ããŒã«ããã¯ããšã©ãŒã®ãã°èšé²ãããã³ã¯ã©ã€ã¢ã³ããžã®æ£ããã¡ãã»ãŒãžã®è¿ä¿¡ã§ãã
ãã®åäœãå®è£ ããŠã¿ãŸãããããŸãããŠãŒã¶ãŒãäœæãããµãŒãã¹ãäœæããŸãããŸãããŠãŒã¶ãŒãååšãããã©ããã確èªããŸãããã®å Žåããšã©ãŒãã¹ããŒãããŸããå¥ã®ã±ãŒã¹ã§ã¯ããã¹ã¯ãŒããããã·ã¥ããããŠãŒã¶ãŒãããŒã¿ããŒã¹ã«ä¿åãããŸãã
LoginService
package com.intetm.service.login; import com.intetm.db.dao.UserDao; import com.intetm.db.entity.Authority; import com.intetm.db.entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.transaction.annotation.Transactional; public class LoginService { @Autowired private UserDao userDao; @Autowired private PasswordEncoder encoder; @Transactional public User createUser(String userName, String password, Authority authority) throws UserExistsException { if (userDao.isUserExsist(userName)) { throw new UserExistsException(userName); } String hash = encoder.encode(password); User user = new User(userName, hash, authority); userDao.persist(user); return user; } public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } public PasswordEncoder getEncoder() { return encoder; } public void setEncoder(PasswordEncoder encoder) { this.encoder = encoder; } }
圌ã«ãã£ãŠã¹ããŒãããäŸå€ã
UserExistsException
package com.intetm.service.login; public class UserExistsException extends Exception { public UserExistsException(String userName) { super("User " + userName + " already exists!"); } }
LoginControllerã§ãäœæèŠæ±ãåŠçããã¡ãœãããè¿œå ããŸãã2ã€ã®ãã©ã¡ãŒã¿ãŒïŒãŠãŒã¶ãŒããã¹ã¯ãŒãïŒãåãåãããŠãŒã¶ãŒã®ç°¡åãªèª¬æãè¿ããããšã©ãŒãã¹ããŒããŸããããã¯ã¢ããªã±ãŒã·ã§ã³ãšã©ãŒã§ã¯ãªããäžæ£ãªããŒã¿ã§ããããã°èšé²ã®å¿ èŠããªããããStacktraceã¯ä¿åããŸããã
@RequestMapping(value = "/createUser", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST) @ResponseBody public UserDetails createUser(@RequestParam String username, @RequestParam String password) throws ServiceException { try { User user = loginService.createUser(username, password, ROLE_USER); return new UserDetails(user); } catch (UserExistsException exception) { throw new ServiceException(exception.getMessage()); } }
LoginController
package com.intetm.web.login; import com.intetm.db.entity.User; import com.intetm.service.login.LoginService; import com.intetm.service.login.UserExistsException; import com.intetm.web.exception.ServiceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import static com.intetm.db.entity.Authority.ROLE_USER; @Controller public class LoginController { private static final Logger logger = LoggerFactory.getLogger(LoginController.class); private static final String HELLO_VIEW = "hello"; @Autowired private LoginService loginService; @RequestMapping(value = "/hello", method = RequestMethod.GET) public String hello(Model model) { logger.debug("hello page"); model.addAttribute("subject", "world"); return HELLO_VIEW; } @RequestMapping(value = "/createUser", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST) @ResponseBody public UserDetails createUser(@RequestParam String username, @RequestParam String password) throws ServiceException { try { User user = loginService.createUser(username, password, ROLE_USER); return new UserDetails(user); } catch (UserExistsException exception) { throw new ServiceException(exception.getMessage()); } } }
JSONã«å€æãããæ»ããªããžã§ã¯ãã
ãŠãŒã¶ãŒè©³çŽ°
package com.intetm.web.login; import com.intetm.db.entity.Authority; import com.intetm.db.entity.User; import java.util.List; class UserDetails { private String userName; private List<Authority> authorities; public UserDetails(User user) { this.userName = user.getUserName(); this.authorities = user.getAuthorities(); } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public List<Authority> getAuthorities() { return authorities; } public void setAuthorities(List<Authority> authorities) { this.authorities = authorities; } }
ãšã©ãŒããã£ããããŠæ£ããåŠçããããã ãã«æ®ããŸãããããè¡ãã«ã¯ãã¢ã·ã¹ã¿ã³ãã¯ã©ã¹ãäœæããŸãã@ControllerAdviceã¢ãããŒã·ã§ã³ã§ã¿ã°ä»ããããŠããŸã
ãèŠæ±åŠçäžã«ãšã©ãŒãçºçããå ŽåãSpringã¯ExceptionHandlerã¢ãããŒã·ã§ã³ã䜿çšããŠå ã®ã³ã³ãããŒã©ãŒãšãã«ããŒã§ã¡ãœãããæ¢ããŸãããšã©ãŒã¯ã©ã¹ãäžèŽããå Žåããã®ã¡ãœãããåŒã³åºãããã¡ãœããã®çµæãã¯ã©ã€ã¢ã³ãã«è¿ãããŸããããã«ããããšã©ãŒãçºçããŠæ£ãããã°ã«èšé²ãããå Žåã§ããæå³ã®ããçµæãè¿ãããšãã§ããŸãã
ExceptionController
package com.intetm.web.exception; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; @ControllerAdvice public class ExceptionController extends ResponseEntityExceptionHandler { private static final Logger logger = LoggerFactory.getLogger(ExceptionController.class); @ExceptionHandler(ServiceException.class) @ResponseBody @ResponseStatus(code = HttpStatus.BAD_REQUEST) public String handleServiceException(ServiceException ex) { if (ex.isNeedLogging()) { logger.error(ex.getMessage(), ex); } return ex.getMessage(); } @ExceptionHandler(RuntimeException.class) @ResponseBody @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) public String handleException(RuntimeException ex) { logger.error(ex.getMessage(), ex); return ex.getMessage(); } }
ã³ã³ãããŒã©ãŒã«ãã£ãŠã¹ããŒãããäŸå€ãããã©ã«ãã§ã¯ãããã¯ããŒã¿ãšã©ãŒã§ããããããã°ã«èšé²ãã¹ãã§ã¯ãªããšèŠãªãããŸãã
ServiceException
package com.intetm.web.exception; public class ServiceException extends Exception { private boolean needLogging = false; public ServiceException() { super(); } public ServiceException(String message) { super(message); } public ServiceException(boolean needLogging) { super(); this.needLogging = needLogging; } public ServiceException(String message, boolean needLogging) { super(message); this.needLogging = needLogging; } public boolean isNeedLogging() { return needLogging; } public void setNeedLogging(boolean needLogging) { this.needLogging = needLogging; } }
javascriptã«éä¿¡ã³ãŒããè¿œå ããŸãã
login.js
$(function () { $("#tabs").tabs(); }); $(document).ready(function () { var frm = $("#formCreate") frm.submit(function (event) { event.preventDefault(); $.ajax({ type: frm.attr('method'), url: frm.attr('action'), data: frm.serialize(), success: function (data) { alert('Username:' + data.userName + "\nrole:" + data.authorities[0]); }, error: function (xhr, str) { alert('User exist!'); } }); return false; }); });
ããã€ãã®å°ããªããšãããããšãæ®ã£ãŠããŸããJavaãªããžã§ã¯ããJSONã«å€æããBeanãè¿œå ããŸãã
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="jacksonMessageConverter"/> </list> </property> </bean>
ã©ã€ãã©ãªæ¥ç¶
build.gradle java json.
settings.gradle
compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: gradle.jacksonVersion compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: gradle.jacksonVersion
buildscript { repositories { mavenLocal() mavenCentral() jcenter() } dependencies { classpath group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } } plugins { id "org.akhikhl.gretty" version "1.2.4" id 'org.liquibase.gradle' version '1.1.1' id "com.eriwen.gradle.js" version "1.12.1" id "com.eriwen.gradle.css" version "1.11.1" } group 'com.intetm' version '0.1' apply plugin: 'java' apply plugin: 'war' apply from: 'database.gradle' //noinspection GroovyUnusedAssignment sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile group: 'javax', name: 'javaee-api', version: gradle.javaxVersion runtime group: 'org.springframework', name: 'spring-jdbc', version: gradle.springVersion compile group: 'org.springframework', name: 'spring-webmvc', version: gradle.springVersion compile group: 'org.springframework', name: 'spring-orm', version: gradle.springVersion compile group: 'org.springframework', name: 'spring-tx', version: gradle.springVersion compile group: 'org.springframework.security', name: 'spring-security-web', version: gradle.springSecurityVersion runtime group: 'org.springframework.security', name: 'spring-security-config', version: gradle.springSecurityVersion runtime group: 'org.hibernate.javax.persistence', name: 'hibernate-jpa-2.1-api', version: gradle.hibernateJpaVersion runtime group: 'org.hibernate', name: 'hibernate-core', version: gradle.hibernateVersion runtime group: 'org.hibernate', name: 'hibernate-entitymanager', version: gradle.hibernateVersion compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: gradle.jacksonVersion compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: gradle.jacksonVersion compile group: 'org.slf4j', name: 'slf4j-api', version: gradle.slf4jVersion runtime group: 'ch.qos.logback', name: 'logback-classic', version: gradle.logbackVersion runtime group: 'org.apache.taglibs', name: 'taglibs-standard-impl', version: gradle.jstlVersion gretty group: 'org.hsqldb', name: 'hsqldb', version: gradle.hsqldbVersion } def serverHttpPort = project.properties['serverHttpPort'] ?: gradle.serverHttpPort def serverResourcesPath = project.properties['serverResourcesPath'] ?: gradle.serverResourcesPath def serverContextFile = project.properties['serverContextFile'] ?: gradle.serverContextFile def serverClassPath = [project.properties['serverClassPath'] ?: gradle.serverClassPath] as Set def dbUser = project.properties['dbUser'] ?: gradle.dbUser def dbPassword = project.properties['dbPassword'] ?: gradle.dbPassword def dbUrl = project.properties['dbUrl'] ?: gradle.dbUrl gretty { httpPort = serverHttpPort serverConfigFile = serverContextFile classPath = serverClassPath inplaceMode = "hard" } task copyEnvironment(type: Copy) { group = 'develop' from 'src/test/resources/environment' into serverResourcesPath } liquibase { activities { //noinspection GroovyAssignabilityCheck main { changeLogFile 'src/sql/main/changelog.xml' url dbUrl username dbUser password dbPassword } dev { changeLogFile 'src/sql/dev/changelog.xml' url dbUrl username dbUser password dbPassword } } } task updateDbMain(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main' tasks.update.execute() } } task updateDbDev(dependsOn: startDatabase) { group = 'develop' doLast { liquibase.runList = 'main, dev' tasks.update.execute() } } javascript.source { login { js { srcDir "src/main/js/login" include "*.js" } } } combineJs { source = javascript.source.login.js.files //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/js/combine/login.js") } minifyJs { source = combineJs //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/js/min/login.js") //sourceMap = file("${buildDir}/js/min/login.sourcemap.json") closure { warningLevel = 'QUIET' } } css.source { login { css { srcDir "src/main/css/login" include "*.css" } } } combineCss { source = css.source.login.css.files //noinspection GrReassignedInClosureLocalVar dest = file("${buildDir}/css/combine/login.css") } minifyCss { source = combineCss dest = file("${buildDir}/css/min/login.css") yuicompressor { // Optional lineBreakPos = -1 } } def dev = true; task copyJs(type: Copy) { group = 'develop' from(dev ? combineJs : minifyJs) as String into "src/main/webapp/js" } task copyCss(type: Copy) { group = 'develop' from(dev ? combineCss : minifyCss) as String into "src/main/webapp/css" } compileJava.dependsOn.add(copyJs) compileJava.dependsOn.add(copyCss)
settings.gradle
gradle.ext.jacksonVersion = '2.3.0'
rootProject.name = 'gull' //lib version gradle.ext.springVersion = '4.2.2.RELEASE' gradle.ext.springSecurityVersion = '4.0.2.RELEASE' gradle.ext.javaxVersion = '7.0' gradle.ext.hibernateVersion = '5.0.2.Final' gradle.ext.hibernateJpaVersion = '1.0.0.Final' gradle.ext.slf4jVersion = '1.7.13' gradle.ext.logbackVersion = '1.1.3' gradle.ext.hsqldbVersion = '2.3.2' gradle.ext.jacksonVersion = '2.3.0' gradle.ext.jstlVersion = '1.2.5' //default server config gradle.ext.serverHttpPort = 8080 gradle.ext.serverResourcesPath = "dev/resources" gradle.ext.serverContextFile = "src/test/resources/environment/jetty-context.xml" gradle.ext.serverClassPath = "src/test/resources/environment/classpath" //default database config gradle.ext.dbName = "xdb" gradle.ext.dbFile = "dev/database/devDB" gradle.ext.dbUser = "SA" gradle.ext.dbPassword = "password" gradle.ext.dbPort = 9001 gradle.ext.dbHost = "localhost" gradle.ext.dbUrl = "jdbc:hsqldb:hsql://${gradle.dbHost}:${gradle.dbPort}/${gradle.dbName}" gradle.ext.dbDrive = "org.hsqldb.jdbc.JDBCDriver"
ãã©ã³ã¶ã¯ã·ã§ã³ã¢ãããŒã·ã§ã³ãæå¹ã«ããŸãã
<tx:annotation-driven transaction-manager="transactionManager"/>
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- jsp view --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:view-controller path="/" view-name="index"/> <mvc:view-controller path="/login" view-name="login"/> <mvc:resources mapping="/js/**" location="/js/"/> <mvc:resources mapping="/css/**" location="/css/"/> <!-- mvc --> <mvc:annotation-driven/> <!-- --> <context:component-scan base-package="com.intetm.web"/> <tx:annotation-driven transaction-manager="transactionManager"/> <bean id="loginService" class="com.intetm.service.login.LoginService"/> <bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="jacksonMessageConverter"/> </list> </property> </bean> </beans>
å€ãã®ã¯ã©ã¹ãäœæãããŠããããšã«æ°ä»ããããããŸãããããã¯ãã¯ã©ã¹ã®è²¬ä»»ãšè²¬ä»»ãåé¢ããè©Šã¿ã§ãããã®åé¢ã¯å®å šã§ã¯ãªããåãªãäŸã§ãããããæå³ããã¯ã©ã¹å¥çŽã¯æ¬¡ã®ãšããã§ãã
1ïŒDao-ããŒã¿ããŒã¹ã®æ¯èŒçäœã¬ãã«ã®äœæ¥ãããŒã¿ã®ä¿åãèªã¿èŸŒã¿ãæŽæ°ãå®è¡æã«ãã©ã³ã¿ã€ã äŸå€ãã¹ããŒããŠããªã¯ãšã¹ãã®åŠçãå®å šã«äžæããå ŽåããããŸãã
2ïŒãµãŒãã¹-ä»äºã®äž»ãªè«çããšã³ããªãã€ã³ãã§ãããããªãã¯ã¡ãœããã¯ããã©ã³ã¶ã¯ã·ã§ã³ãšããŠããŒã¯ãããŸããèŠæ±åŠçäžã«ãDaoã¡ãœãããç¹°ãè¿ãåŒã³åºãããšããããŸãããåŒã³åºãã¯åããã©ã³ã¶ã¯ã·ã§ã³å ã§çºçããŸãããªã¯ãšã¹ãã®åŠçå šäœã«å¯Ÿããåäžã®ãã©ã³ã¶ã¯ã·ã§ã³ã«ããããšã©ãŒãçºçãããšãã«è¡ããããã¹ãŠã®å€æŽãç°¡åã«ããŒã«ããã¯ã§ããŸãã
泚éã®çµæãããããç解ããã«ã¯ãäœæ¥ã®ååãç¥ãå¿ èŠããããŸãã圌ã«é ãããŠãããã®ã¯äœããããŸããããã®ãã©ã³ã¶ã¯ã·ã§ã³ã確èªãããšãSpringã¯ããã±ãŒãžBeanããããã·ã§ã©ããããŸãããããã·ã³ãŒãã¯ã次ã®ããã«æŠç¥çã«è¡šãããšãã§ããŸã
public void someMethod(){ transaction.open(); try{ subject.someMethod(); } catch(Exception exception){ transaction.setRollbackOnly(true); } finally { transaction.close(); } }
ã€ãŸããã¡ãœãããåŒã³åºããããšããããã·ã¯æåã«ãããã·ã«å ¥ããŸãããããã·ã¯ããã©ã³ã¶ã¯ã·ã§ã³ãéãããšã©ãŒãçºçããå Žåã«å ã®ã¡ãœãããåŒã³åºãããã©ã³ã¶ã¯ã·ã§ã³ãããŒã«ããã¯ããå¿ èŠãããããšãããŒã¯ããåŒã³åºãã¯ã©ã¹ã«å¶åŸ¡ãæ»ãåã«ãã©ã³ã¶ã¯ã·ã§ã³ãéããŸããããããã®äœæ¥æ¹æ³ãç解ãããšã2ã€ã®éèŠãªçµè«ãå°ãåºãããšãã§ããŸãã
泚éãä»ããããã¡ãœããã®å®è¡ãå®äºãããšããã©ã³ã¶ã¯ã·ã§ã³ã¯èªåçã«éããããå€æŽãããŒã«ããã¯ã§ããªããªããŸãããããã£ãŠããã©ã³ã¶ã¯ã·ã§ã³ãéãããéãããããå¿ èŠãããã®ã¯Serviceã¡ãœããã§ããäžéšã®ãã¬ãŒãã³ã°äŸã§ã¯ããã©ã³ã¶ã¯ã·ã§ã³ã¯Daoã¬ãã«ã§éãããŸãããããã¯æ ¹æ¬çã«ééã£ãŠããŸãã Serviceã¡ãœããå ã§2ã€ã®é£ç¶ããDaoåŒã³åºããè¡ãããå Žåã2çªç®ã®åŒã³åºãã§ãšã©ãŒãçºçããå Žåãæåã®åŒã³åºãã®çµæã¯ããŒââã¿ããŒã¹ã«æ®ããŸãïŒå®éã2åç®ã®åŒã³åºããŸã§ã«ãæåã®ãã©ã³ã¶ã¯ã·ã§ã³ã¯ãã§ã«æ£åžžã«çµäºããŠããŸããïŒ
2çªç®ã®çµè«ã¯ãã£ãšç°¡åã§ãããã©ã³ã¶ã¯ã·ã§ã³ãéãããã«ãããã·ã䜿çšããããããåŒã³åºãã¯å¥ã®Beanããè¡ãããå¿ èŠããããŸãããããã·ã¯ç°ãªãBeanéã®åŒã³åºãã«åã蟌ãŸããã¯ã©ã¹å ã®ã¡ãœããåŒã³åºããã€ã³ã¿ãŒã»ããããæ©èœã¯ãããŸããã
ãšã©ãŒåŠçã§ã¯ã©ã¹ã®è²¬ä»»ã«æ»ããšããµãŒãã¹ã®åäœã¯æ¬¡ã®ããã«ãªããŸãããã¹ãŠããšã©ãŒãªãã§çµäºããå Žåãã¯ã©ã¹ã¯åã«çµæãè¿ããŸãã Daoã¡ãœããåŒã³åºãã®å ¥åã§ãšã©ãŒãçºçãããšããšã©ãŒãã¹ããŒãããå€æŽãããŒã«ããã¯ãããŸãã
ã©ã³ã¿ã€ã ãšã©ãŒã«å ããŠããµãŒãã¹ã¯ãã§ãã¯äŸå€ãã¹ããŒããå ŽåããããŸããã¯ã©ã€ã¢ã³ãã®ãªã¯ãšã¹ããæ£ãããªãå Žåã¯ç Žæ£ããããã®çç±ãããããŸããããšãã°ãäžèŽããååãæã€ãŠãŒã¶ãŒãäœæããããšããŸããããã¯ã¢ããªã±ãŒã·ã§ã³ãšã©ãŒã§ã¯ãªããããç¹å¥ãªæ¹æ³ã§åŠçããå¿ èŠããããŸãããã®ãããªã¯ãšãªã¯ãããã»ã¹ã®ããžãã¯ã«å¿ããŠãããŒã¿ããŒã¹ãå€æŽããããšãã§ããŸãã
泚æïŒããã©ã«ãã§ã¯ãããŒã«ããã¯ã¯ã©ã³ã¿ã€ã äŸå€ã®å Žåã«ã®ã¿çºçããŸããå€æŽãããŒã«ããã¯ããããã§ãã¯ãããäŸå€ãçºçããããã«ããã«ã¯ãrollbackForãã©ã¡ãŒã¿ãŒã䜿çšããŠå€æŽãè¿œå ã§æå®ããå¿ èŠããããŸããã³ãŒãäŸïŒ
@Transactional(rollbackFor = Exception.class) public void someMethod() throws Exception { ... }
次ã«ãäŸå€ãé€ããå€æŽã®ããŒã«ããã¯ãè¡ãããŸãã
3ïŒã³ã³ãããŒã©ãŒ-èŠæ±ãåãå ¥ããŸããæå°å€ã¯ãããåŠçãããµãŒãã¹ã«æž¡ããŸãããµãŒãã¹ããæ£åžžãªå¿çãåä¿¡ããå Žå-å¿çãçæããŸãããã§ãã¯ããããšã©ãŒã¯ãå¿ èŠã«å¿ããŠé©åãªã³ã³ããã«åããã±ãŒãžåãããæ®ãã¯æ¬¡ã®ã¬ãã«ã«è»¢éãããŸãããã®åœ¹å²ã¯éèŠã§ã¯ãªãããã«èŠããŸããããµãŒãã¹ãšããŒãžããããšããªãã§ãã ãããæåã®æ®µéã§ã¯ããšã³ããªãã€ã³ãã¯1ã€ã§ããããã®æ°ã¯å¢ããå¯èœæ§ããããŸããããšãã°ãAPIã䜿çšããŠã¢ãã€ã«ã¯ã©ã€ã¢ã³ããè¿œå ããŸãã
4ïŒã³ã³ãããŒã©ãŒã®ã¢ããã€ã¹-ã³ã³ãããŒã©ãŒã®è¿œå ã¯ã©ã¹ã¯ããšã©ãŒã®åŠçã«åœ¹ç«ã¡ãŸãããã¹ãŠã®ã©ã³ã¿ã€ã äŸå€ãã€ã³ã¿ãŒã»ãããããã°ã«èšé²ãäœæããã¯ã©ã€ã¢ã³ãã«å¿ èŠãªæå°éã®æ å ±ã®ã¿ãæäŸããŸãããã§ãã¯äŸå€ã®å Žåãç¶æ³ã¯ç°ãªããŸãããããããã¹ãŠã€ã³ã¿ãŒã»ãããããŸãããç¹å¥ãªãã©ã°ã®ä»ãããšã©ãŒã®ã¿ããã°ã«èšé²ãããŸããåæ§ã®éãã¯ããšã©ãŒã®æ§è³ªã«ãããã®ã§ããåè ã¯å®éã«ã¯ã¢ããªã±ãŒã·ã§ã³ãšã©ãŒã§ããããã°ã€ã³ããå¿ èŠããããŸããå¶åŸ¡ãããäŸå€ã¯ããŠãŒã¶ãŒãå ¥åããããŒã¿ã®äžæ£ç¢ºãã®ã¿ã衚瀺ãããã°ã«èšèŒããå¿ èŠã¯ãããŸããã
ãããã«
çµæã®äŸã¯å°ããªãHelloãworldïŒããšããŸã䌌ãŠããŸãããããã¹ãŠã§ã¯ãªãåºæ¬çãªã³ã³ããŒãã³ãã®ã¿ãå«ãŸããŠããŸãããã¹ããããŒã«ã©ã€ãºãªã©ã®è¹å€ã®ãã®ã¯åãæ®ãããŸããããããããªããã°ãã¢ããªã±ãŒã·ã§ã³ãå®äºãããšèŠãªãããšã¯ã§ããŸããã
ã¢ããªã±ãŒã·ã§ã³ã®ãœãŒã¹ã³ãŒãã¯githubã§å ¥æã§ããŸããæã¡äžãã¯2è¡ã§è¡ãããŸãã
gradlew updateDbDev gradlew jettyStart
å¿ èŠãªã®ã¯ãJDKã®ã€ã³ã¹ããŒã«ã ãã§ããä»ã®ãã¹ãŠã®äŸåé¢ä¿ã¯ãã®å Žã§èµ·åããŸããããããåæã«ãã¢ããªã±ãŒã·ã§ã³ã¯ã¢ããªã·ãã¯ã§ã¯ãããŸãããå¿ èŠã«å¿ããŠãããŒã¿ããŒã¹ãããŒã«ã«ã§å€éšããŒã¿ããŒã¹ã«çœ®ãæããå€éšãµãŒãã¬ããã³ã³ããã䜿çšããVCSãšç«¶åããããšãªããã®ã³ã°ããªã·ãŒãèšå®ã§ããŸãã