Share
Embed
Spring Boot で Boot した後に作る Web アプリケーション基盤/spring-boot-application-infrastructure
JJUG CCC 2016 Spring で発表した時の資料です。
sinsengumi
May 21, 2016
Transcript
88 slides
-
> < 2 JJUG CCC 2016 Spring. 2016/05/21 • ໊લ
: ٢ా ๎ / @sinsengumi • ৬ۀ : ιϑτΣΞΤϯδχΞ • ओʹαʔόʔαΠυΛ୲ • ࠷ॳ Web σβΠφʔΛ͍ͯ͠·ͨ͠ • SIer ͔ΒΤϜεϦʔגࣜձࣾస৬ • ॴଐ : ΤϜεϦʔגࣜձࣾ • 3 • Spring ྺ : 2 ͘Β͍ • JJUG ॳࢀՃʂ ࣗݾհ -
> < 3 JJUG CCC 2016 Spring. 2016/05/21 ձࣾհʢΤϜεϦʔגࣜձࣾʣ •
ຊͷҩࢣ 8 ׂɺੈքͰ 350 ສਓͷҩࢣ͚αʔϏεΛӡӦ͢Δ ҩྍܥϕϯνϟʔاۀ • ϛογϣϯ : ΠϯλʔωοτͷྗͰҩྍΛมֵ͢Δ • ւ֎ల։ɺ࣏ݧɾήϊϜͳͲ৽ࣄۀੵۃత • JavaɺJVMʢScalaɾKotlinʣΛଟͷαʔϏεͰར༻ ΤϯδχΞৗʹืूதʂ https://jobs.m3.com/engineer Medicine − ҩྍ Media − ϝσΟΞ Metamorphosis − มֵ ϋοΧιϯͷ༷ࢠ -
> < 4 JJUG CCC 2016 Spring. 2016/05/21 ࣍ 1.
Spring Boot ʹ͍ͭͯ 2. Boot ͨ͠ɺͦͷޙɾɾɾ 1. URL ઃܭ 2. ྫ֎ 3. τϥϯβΫγϣϯ 4. όον 5. ϓϩύςΟ 6. ϩΪϯά 7. ηΩϡϦςΟ 8. ͦͷଞ 3. ·ͱΊ -
> < 6 JJUG CCC 2016 Spring. 2016/05/21 • Java
EE (JAX-RS, CDI, JPA, JSF) • Play Framework • Struts2 • Seasar2 • Dropwizard, Ninja etc • Spring (not Boot) օ͞Μɺ৽نʹ Java ͰΞϓϦέʔγϣϯΛ࡞Ζ͏ͱࢥͬͨ࣌ɺ ࠓʢ2016ݱࡏʣͳΒԿΛબͼ·͔͢ʁ Spring Boot ʹ͍ͭͯʢ1ʣ ͏ʔΜɾɾɾɾ ॏްա͗Δ͠ɺJava EE αʔόʔͷ४උ͕ɾɾ Java ൛αϙʔτΒΕͦ͏Ͱා͍ɾɾɾ ͳΜ͔੬ऑੑ͕ɾɾɾ 20169݄ʹ EOL ۀͰऔΓΉʹ·ͩ·ͩރΕͯͳͦ͞͏ Spring Boot ͕͋Δࠓɾɾɾ -
> < 7 JJUG CCC 2016 Spring. 2016/05/21 Spring Boot
ʹ͍ͭͯʢ2ʣ ͦ͜ͰɺSpring Boot ʂ SPRING INITIALIZR Λ͑ɺಈ͘ΞϓϦέʔγϣϯ͕͙͢Ͱ͖Δɻ https://start.spring.io/ 1. SPRING INITIALIZR ʹΞΫηε͠ɺ͍͍ͨػೳΛબ͠ɺDLɻ 2. DL ͨ͠ Zip Λղౚ͢Δɻ 3. mvn spring-boot:run ͢Δɻ ʢ͘͠ IDE ͔Β main ϝιουΛୟ͘ʣ -
> < 8 JJUG CCC 2016 Spring. 2016/05/21 Spring Boot
ʹ͍ͭͯʢ3ʣ [demo] mvn spring-boot:run [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building demo 0.0.1-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] >>> spring-boot-maven-plugin:1.3.3.RELEASE:run (default-cli) > test-compile @ demo >>> [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ demo --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] Copying 1 resource [INFO] Copying 0 resource [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ demo --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to /Users/sinsengumi/Downloads/spring-init/demo/target/classes [INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ demo --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory /Users/sinsengumi/Downloads/spring-init/demo/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ demo --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to /Users/sinsengumi/Downloads/spring-init/demo/target/test-classes [INFO] [INFO] <<< spring-boot-maven-plugin:1.3.3.RELEASE:run (default-cli) < test-compile @ demo <<< [INFO] [INFO] --- spring-boot-maven-plugin:1.3.3.RELEASE:run (default-cli) @ demo --- . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v1.3.3.RELEASE) ͓͓ʔײಈ -
> < 9 JJUG CCC 2016 Spring. 2016/05/21 Boot ૣ͍͕ɾɾɾʢ1ʣ
ʮΑʔ͠ɺ͡Ό͋ૣ࡞Γ࢝ΊͪΌ͏ͧʔʯ ޙɾɾɾɾ ʮ͑ʔͱɺྫ֎ॲཧͲ͏͢Δͷ͕͍͍Μͩʁʯ ʮτϥϯβΫγϣϯ͔͚͍ͨΜ͚ͩͲɾɾɾʯ -
> < 12 JJUG CCC 2016 Spring. 2016/05/21 Boot ૣ͍͕ɾɾɾʢ4ʣ
Boot ͔֬ʹૣ͍ʂ ͕ɺ͔ͦ͜Β Spring ͷੈքɻࢼ͞ΕΔ Spring ྗɾɾɾʂ ʢࢁͷϥΠϒϥϦɺΈ߹ΘͤɺSpring ͷࣝʣ ͦ͜ͰɺຊηογϣϯͰɺ Spring Boot Λ༻͍ͨී௨ͷ Web ΞϓϦέʔγϣϯΛ࡞͢Δࡍʹɺ ࠷ॳʹΔ͖ΞϓϦέʔγϣϯج൫ͷߏஙΛ Spring ͰͲ͏͢Δͷ͔ʁ Λத৺ʹ͓͠͠·͢ɻ ΰʔϧ ʰػೳ։ൃ Readyʱͳঢ়ଶΛ࡞Δ͜ͱ -
> < 13 JJUG CCC 2016 Spring. 2016/05/21 Boot ૣ͍͕ɾɾɾʢ5ʣ
େํ • Spring ͷํʹै͏ʢRail ʹΔతͳʣ @Controller, @Service, @Repository ΛͬͨجຊతͳϨΠϠʔߏ • ίʔυΛͳΔ͘ॻ͔ͳ͍ ॻ͔ͳ͍ͨΊʹϑϨʔϜϫʔΫΛ͍ͬͯΔ • ۀػೳΛ࡞Δ࣌ʹɺ·Βͳ͍ɺ·ͳ͍Α͏ͳઃܭ -
> < 15 JJUG CCC 2016 Spring. 2016/05/21 • Ͳ͏͍͏
URL ମܥ͕͋Δ͔ʁ ݴ͍͑ΔͱɺʮαʔϏεׂʯΛݕ౼͢Δͱ͍͏͜ͱ • ओʹɺϢʔβը໘ɺཧը໘ɺAPIʢ֎͖ɺ͖ʣΛ ಉҰΞϓϦ্ʹࡌͤΔ͔ʁɺผΞϓϦʹ͢Δ͔ʁͱ͍͏ɻ microservices తʹׂͨ͠΄͏͕ྑ͍͕ɺ Πϯϑϥίετͷ૿େɺΞϓϦɾϏδωεͷنʹΑΔͣɻ ͍͖ͳΓ Spring ͱؔͳ͍Ͱ͕͢ɺ Web ΞϓϦΛ࡞Δ্Ͱ؊৺ͳͱ͜ΖͳͷͰ·ͣ͡Ίʹݕ౼͠·͢ɻ ػೳ։ൃΛ͢Δલʹ URL ઃܭʹ͍ͭͯߟ͍͑ͨ͜ͱʢ1ʣ -
> < 16 JJUG CCC 2016 Spring. 2016/05/21 • Ϣʔβը໘
[ / ] • ཧը໘ [ /admin ] • API ֎͖ [ /api ] • API ͖ [ /api/internal ] ຊηογϣϯͰ ಉҰΞϓϦʹ͜ΕΒΛڞଘͤ͞Δ͜ͱΛલఏͱͯ͠Λ͠·͢ɻ ػೳ։ൃΛ͢Δલʹ URL ઃܭʹ͍ͭͯߟ͍͑ͨ͜ͱʢ2ʣ -
> < 17 JJUG CCC 2016 Spring. 2016/05/21 URL ઃܭΛίʔυͰදݱ͓ͯ͘͠ʢ1ʣ
Ϣʔβը໘ɺཧը໘ɺAPIʢ֎͖ɺ͖ʣΛ enum Ͱఆٛ͢Δɻ @AllArgsConstructor @Getter public enum Site { API_INTERNAL("APIʢ͖ʣ", "/api/internal", false), API_EXTERNAL("APIʢ֎͖ʣ", "/api", false), SCREEN_ADMIN("ཧը໘", "/admin", true), SCREEN_USER("Ϣʔβը໘", "", true); private String label; private String baseUrl; private boolean protectCsrf; // ྻڍࢠͷॱ൪Λม͑Δͱɺޡఆ͢ΔͷͰҙɻ public static Site of(String url) { if (url == null) { return SCREEN_USER; } for (Site location : values()) { if (url.startsWith(location.baseUrl)) { return location; } } return SCREEN_USER; } } enum Ͱ URL ମܥΛఆٛ͢Δ URL ͔ΒͲ͜ʹΞΫηε͍ͯ͠Δ͔ Λఆ͢ΔϝιουΛ༻ҙ͓ͯ͘͠ -
> < 18 JJUG CCC 2016 Spring. 2016/05/21 URL ઃܭΛίʔυͰදݱ͓ͯ͘͠ʢ2ʣ
ίʔυͱͯ͠දݱ͢Δ͜ͱͰɺ͍ΖΜͳ໘Ͱ͑ΔͷͰɺΦεεϝͰ͢ɻ ʢfilter, interceptor ͷఆٛΛ͢ΔࡍɺύεΛϋʔυίʔυ͠ͳ͍ͰࡁΉͳͲɻ ৄ͘͠ޙड़ʣ ͪΖΜɺController Ϋϥεͷ package Site ຖʹ͚·͢ɻ src/main/java/com/example !"" Application.java !"" controller # !"" Site.java # !"" api # # !"" external # # # $"" HelloController.java # # $"" internal # # $"" HelloController.java # $"" screen # !"" admin # # $"" HelloController.java # $"" user # $"" HelloController.java -
> < 20 JJUG CCC 2016 Spring. 2016/05/21 ػೳ։ൃΛ͢Δલʹྫ֎ʹ͍ͭͯߟ͍͑ͨ͜ͱʢ1ʣ •
ྫ֎͕ى͖ͨ࣌ʹԿΛ͢Δ͔ʁʢϩΪϯάɺ௨ etcʣ • ྫ֎͕ى͖ͨ࣌ʹͲ͜ߦ͔͘ʁʢը໘ͷ߹ɺAPI ͷ߹ʣ • εςʔλείʔυͪΌΜͱઃఆ͍ͨ͠ • ݕࠪྫ֎ɺඇݕࠪྫ֎ͷ༻ํ • ͯ͢ͷྫ֎Λิ͍ͨ͠ʢTomcat ͷΤϥʔը໘ग़Δͱ͔μα͍ʣ • ͍ͬͯΔϑϨʔϜϫʔΫͰɺͲ͏ॲཧ͖͔͢ఆ͍ٛͯ͠Δ͔ʁ ʢSpring తʹʁʣ -
> < 21 JJUG CCC 2016 Spring. 2016/05/21 ػೳ։ൃΛ͢Δલʹྫ֎ʹ͍ͭͯߟ͍͑ͨ͜ͱʢ2ʣ ౷Ұͨ͠ྫ֎ॲཧΛ͍ͨ͠
FW ʹඇݕࠪྫ֎Λ Throw ͢Δ͚ͩ -
> < 22 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot (MVC) ͰͲ͏͢Δ͔ʁʢ1ʣ • Filter • ˏController ͷ Interceptor • ݸผͷ @Controller ʹ @ExceptionHandler • @ResponseStatus Λ༩ͨ͠ྫ֎Λ Throw • @ControllerAdvice Ͱ @ExceptionHandler • Spring Boot ͷ ErrorController Γํ͕ͨ͘͞Μ͋Γ·͢ɻ -
> < 23 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot (MVC) ͰͲ͏͢Δ͔ʁʢ2ʣ • status code ͕ηοτ͞Ε͍ͯͳ͍ • ͯ͢ͷྫ֎ΛิͰ͖ͳ͍ʢϓϨθϯςʔγϣϯɺ404 Τϥʔʣ άϩʔόϧͳྫ֎ॲཧͷํ๏ͱͯ͠ɺ άάΔͱΑ͘ग़ͯ͘Δ @ControllerAdvice ͍͔͕ͭ͋͘Δɻ @Slf4j @ControllerAdvice(“com.example.controller.admin") public class GlobalControllerAdvice { @ExceptionHandler(Exception.class) public String handleException(Exception e, HttpServletResponse response, Model model) { // status code ઃఆ͞Εͯͳ͍ͷͰɺ͜͜Ͱઃఆ͢Δɻ // ͲΜͳ status code Λઃఆ͢Δ͔ Exception ͔Βఆ͢Δඞཁ͕͋Δ͕ɺಠࣗྫ֎ͷ߹͍͍͕ɺ // Spring ͕͛ͯ͘Δྫ֎ʢMissingServletRequestParameterException ͱ͔ʣɾɾɾɾ response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); log.error("Error!!", e); model.addAttribute("stackTrace", ExceptionUtils.getStackTrace(e)); return "admin/error"; } } -
> < 24 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot (MVC) ͰͲ͏͢Δ͔ʁʢ3ʣ 1. ExceptionHandlerExceptionResolver 2. ResponseStatusExceptionResolver 3. DefaultHandlerExceptionResolver Spring Boot ͰɺErrorController ͰΔͷ͕Φεεϝɻ ErrorController ͜ΕΒ͕ద༻͞ΕͨޙʹݺΕΔɺ web.xml ͷ error-page ૬ͷॲཧɻ ʢ͜Ε Spring MVC Ͱͳ͘ɺΈࠐΈͷ ServletContainer ͕ॲཧ͍ͯ͠Δʣ σϑΥϧτͰɺʮWhitelabel Error PageʯΛදࣔ͢Δ BasicErrorController ͱ͍͏ͷ͕࣮͞Ε͍ͯΔɻ ͜ΕΛಠࣗͷ ErrorController ʹஔ͖͑Δɻ Spring MVC ͰɺҎԼͷ HandlerExceptionResolver ͕ॱʹݺΕΔɻ @ExceptionHandler Λॲཧ͢Δ @ResponseStatus Λॲཧ͢Δ FWʢSpringMVCʣͰى͖ͨྫ֎ Λॲཧ͢Δ -
> < 25 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot (MVC) ͰͲ͏͢Δ͔ʁʢ4ʣ ϒϥβʢAccept: text/htmlʣͰΞΫηε͢Δͱɺը໘Λฦ͢ɻ [~] curl http://localhost:8080/admin/hello { "timestamp" : 1462114091743, "status" : 400, "error" : "Bad Request", "exception" : "org.springframework.web.bind.MissingServletRequestParameterException", "message" : "Required String parameter 'name' is not present", "path" : "/admin/hello" } ϒϥβҎ֎ͰΞΫηε͢ΔͱɺJSON Λฦ͢ɻ -
> < 26 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot (MVC) ͰͲ͏͢Δ͔ʁʢ5ʣ 1. ΧελϜ ErrorController ͷ࣮ʢΤϥʔॲཧΛҰखʹҾ͖ड͚Δʣ 2. ֤ Site ຖͷΤϥʔॲཧͷ࣮ʢը໘ͳΒΤϥʔը໘ɺAPI ͳΒ JSONʣ 3. ಠࣗྫ֎ʹ @ResponseStatus Λ͚ͭΔ ͯ͢ͷΤϥʔΛิͭͭ͠ɺ͍͍ײ͡ʹΤϥʔΛॲཧ͢Δɻ application.properties # server.error.path Λઃఆ͢ΔʢσϑΥϧτ /errorʣ server.error.path=/globalError # 404 ͷ࣌ྫ֎Λൃੜͤ͞Δ spring.mvc.throw-exception-if-no-handler-found=true ४උͱͯ͠ɺɺ -
> < @Slf4j @Controller public class GlobalErrorController implements ErrorController {
public static final String ERROR_EXCEPTION = "com.example.demo.error.exception"; @Value("${server.error.path:${error.path:/error}}") private String errorPath; @Autowired private ErrorAttributes errorAttributes; @Override public String getErrorPath() { return errorPath; } @RequestMapping(value = "${server.error.path:${error.path:/error}}") public String error(HttpServletRequest req) { Throwable error = errorAttributes.getError(new ServletRequestAttributes(req)); String requestURI = (String) req.getAttribute("javax.servlet.forward.request_uri"); Site site = Site.of(requestURI); req.setAttribute(ERROR_EXCEPTION, error); log.warn("Caught an error. site = {}, requestURI = {}", site, requestURI); return "forward:" + site.getBaseUrl() + "/error"; } } ΧελϜ ErrorController ͷ࣮ 27 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring Boot (MVC) ͰͲ͏͢Δ͔ʁʢ6ʣ ErrorController ΠϯλϑΣʔεͷ࣮ @RequestMapping ʹΤϥʔ࣌ͷ ࣮ॲཧΛهड़͢Δ Ͳ͜ͰΤϥʔ͕ग़͔ͨΛఆ͢Δ ΤϥʔใΛه͠ɺ ֤ Site ͷΤϥʔॲཧʹ forward ͢Δ -
> < 28 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot (MVC) ͰͲ͏͢Δ͔ʁʢ7ʣ @Slf4j @RestController public class ErrorController { @RequestMapping(value = "/api/internal/error") public ErrorResponse error(HttpServletRequest request) { Throwable e = (Throwable) request.getAttribute(GlobalErrorController.ERROR_EXCEPTION); String errorCode = RandomStringUtils.randomAlphabetic(15); log.error(e.getMessage(), e); return ErrorResponse.build(errorCode, e); } } API ͷΤϥʔॲཧ @Slf4j @Controller public class ErrorController { @RequestMapping("/admin/error") public String error(HttpServletRequest request, Model model) { Throwable e = (Throwable) request.getAttribute(GlobalErrorController.ERROR_EXCEPTION); String errorCode = RandomStringUtils.randomAlphabetic(15); log.error(e.getMessage(), e); model.addAttribute("errorCode", errorCode); model.addAttribute("stackTrace", ExceptionUtils.getStackTrace(e)); return "screen/admin/error"; } } ཧը໘ͷΤϥʔॲཧ ϩάΛు͍ͨΓɺ௨Λͨ͠Γ ϩάΛు͍ͨΓɺ௨Λͨ͠Γ API ͳͷͰɺΤϥʔϨεϙϯεΛฦ͢ ը໘ͳͷͰɺΤϥʔը໘Λฦ͢ -
> < 29 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot (MVC) ͰͲ͏͢Δ͔ʁʢ8ʣ // γεςϜΤϥʔ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public class ApplicationException extends RuntimeException { public ApplicationException(String message) { super(message); } } // ೝՄΤϥʔ @ResponseStatus(HttpStatus.FORBIDDEN) public class AuthorizationException extends RuntimeException { public AuthorizationException(String message) { super(message); } } // NotFound Τϥʔ @ResponseStatus(HttpStatus.NOT_FOUND) public class ItemNotFoundException extends RuntimeException { public ItemNotFoundException(String message) { super(message); } } @ResponseStatus Λ͚ͨྫ֎ΛϏδωεϩδοΫ͔Β Throw ͢Δ -
> < 30 JJUG CCC 2016 Spring. 2016/05/21 ࣮ྫʢAPI ͷ߹ʣʢ1ʣ
@RestController public class HelloController { @RequestMapping("/api/internal/hello") public String hello(@RequestParam("name") String name) { if (name.equals("yoshida")) { throw new AuthorizationException("AuthorizationException error."); } return "Hello. " + name + "͞Μ"; } } @ResponseStatus(HttpStatus.FORBIDDEN) ͷ͍ͭͨ ྫ֎Λ Throw ͢Δ name ͕ແ͍ͱ͖ Spring ͔Β MissingServletRequestParameterException ͕ Throw ͞ΕΔ -
> < 31 JJUG CCC 2016 Spring. 2016/05/21 ࣮ྫʢAPI ͷ߹ʣʢ2ʣ
[~] curl -v http://localhost:8080/api/internal/hello?name=yoshida ... < HTTP/1.1 403 Forbidden ... { "code" : "XNBzNfxhiJedzcj", "message" : "AuthorizationException error.", "errorClass" : "com.example.exception.AuthorizationException" } [~] curl -v http://localhost:8080/api/internal/hello ... < HTTP/1.1 400 Bad Request ... { "code" : "oQhiQAZUmIUMplO", "message" : "Required String parameter 'name' is not present", "errorClass" : "org.springframework.web.bind.MissingServletRequestParameterException" } 400 ͕ઃఆ͞Ε͍ͯΔ 403 ͕ઃఆ͞Ε͍ͯΔ -
> < 32 JJUG CCC 2016 Spring. 2016/05/21 ࣮ྫʢը໘ͷ߹ʣʢ1ʣ @Controller
public class HelloController { @RequestMapping("/admin/hello") public String hello(@RequestParam("name") String name, Model model) { if (name.equals("yoshida")) { throw new AuthorizationException("AuthorizationException error."); } model.addAttribute("name", name); return "screen/admin/hello"; } } @ResponseStatus(HttpStatus.FORBIDDEN) ͷ͍ͭͨ ྫ֎Λ Throw ͢Δ name ͕ແ͍ͱ͖ Spring ͔Β MissingServletRequestParameterException ͕ Throw ͞ΕΔ -
> < 35 JJUG CCC 2016 Spring. 2016/05/21 ·ͱΊ ɿ
ྫ֎ @ResponseStatus Λ͚ͨඇݕࠪྫ֎Λ Throw ͢Δ͚ͩ ͜ΕͰɺྫ֎ ͱ͍͏ɺػೳ։ൃ Ready ͳঢ়ଶʹͳͬͨʂ -
> < 37 JJUG CCC 2016 Spring. 2016/05/21 ػೳ։ൃΛ͢ΔલʹτϥϯβΫγϣϯʹ͍ͭͯߟ͍͑ͨ͜ͱ ʢOR
Ϛούʔɺ͓ΈͷͷΛ͍·͠ΐ͏ɻ ͪͳΈʹɺฐࣾͰ MyBatis, Doma2 ͕Α͘ΘΕΔʣ • τϥϯβΫγϣϯڥքΛͲ͜ʹ͢Δ͔ʁʢController or Service ʣ • Controller ʹ͢Δͱɺ ్தͰҰ commit ͍ͨ͠߹ͳͲྫ֎ରԠ͕ΊΜͲ͍͘͞ • τϥϯβΫγϣϯ͚Ε͍΄͏͕Α͍ • ϏδωεϩδοΫʹτϥϯβΫγϣϯॲཧͷίʔυΛೖΕͨ͘ͳ͍ • connection.commit, connection.rollback ͱ͔ɾɾɾ • ౷ҰతͳτϥϯβΫγϣϯॲཧΛ͍ͨ͠ -
> < 38 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot (Tx) ͰͲ͏͢Δ͔ʁʢ1ʣ @Service ͷϝιουʢ͘͠Ϋϥεʣʹ @Transactional Λ͚Δɻ @Service public class UserService { @Autowired private UserRepository repository; @Transactional public int create(User user) { return repository.create(user); } @Transactional public int update(User user) { return repository.update(user); } public User findById(int id) { return repository.findById(id); } } @Transactional ͷϝιου͕ݺΕͨΒɺ τϥϯβΫγϣϯ͕։࢝͞ΕΔɻ ϝιουΛൈ͚Ε commit, ඇݕࠪྫ֎͕ൃੜͨ͠߹ rollback ɻ ࡉ͔͍ઃఆ @Transactional ͷଐੑͰઃఆՄೳ -
> < 39 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot (Tx) ͰͲ͏͢Δ͔ʁʢ2ʣ ͔͠͠ɺຖճ @Transactional Λॻ͍͍ͯ͘ͷͩΔ͍ɻ ݸผʹ͚Δɾ͚ͳ͍ͷஅΛͨ͘͠ͳ͍ɻ ͚Δ͖ϝιουʹ͍͍ͯͳ͍΄͏͕ɻ ※ ͜ͷ෦͋ΔఔׂΓΓ τϥϯβΫγϣϯॲཧͷ։࢝ɾऴྃίετΛेʹ͍ͷͰɺ select only ͰτϥϯβΫγϣϯॲཧΛ։࢝ͯ͠ͳ͍ͱ͍͏அɻ ͯ͢ͷ Service ϝιουʹ @Transactional Λ͚ͭΔ -
> < 40 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot (Tx) ͰͲ͏͢Δ͔ʁʢ3ʣ AOP Λͬͯɺ @Service ͷͯ͢ͷϝιουʹɺ@Transactional Λ༩͢Δɻ @SpringBootApplication @ImportResource("classpath:transaction-context.xml") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ※ Java Config Ͱ࣮ݱͰ͖ͳ͍Έ͍ͨɻ http://stackoverflow.com/questions/14068525/javaconfig-replacing- aopadvisor-and-txadvice http://qiita.com/ksby/items/2ea40c5455c31870bd7c -
> < <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="লུ"> <tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes> <tx:method name=“*” isolation=“READ_COMMITTED" /> </tx:attributes> </tx:advice> <aop:config> <aop:advisor pointcut="execution(public * com.example.service.*.*(..)) and @target(org.springframework.stereotype.Service)" advice-ref="txAdvice" /> </aop:config> </beans> transaction-context.xml 41 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring Boot (Tx) ͰͲ͏͢Δ͔ʁʢ4ʣ com.example.service Լͷ @Service ͕͍͍ͯΔॴ ͯ͢ͷϝιουʹ༩͢Δͷ͕͕͋Δ߹ɺ ໋໊نʢcreate*, update* ʹͷΈ༩ʣͰɺ༩ରΛܾΊΔͷ͋Γɻ -
> < 42 JJUG CCC 2016 Spring. 2016/05/21 ·ͱΊ ɿ
τϥϯβΫγϣϯ Service ͕τϥϯβΫγϣϯڥքʢࣗಈʣ ͜ΕͰɺτϥϯβΫγϣϯ ͱ͍͏ɺػೳ։ൃ Ready ͳঢ়ଶʹͳͬͨʂ -
> < 44 JJUG CCC 2016 Spring. 2016/05/21 ػೳ։ൃΛ͢Δલʹόονʹ͍ͭͯߟ͍͑ͨ͜ͱʢ1ʣ Web
ΞϓϦͱ͍͑ɺಛఆͷ࣌ؒʹԿ͔Λ͍ͨ͠ͱ͏ཁ݅Α͋͘Δɻ • ձһͷੜʹ͓ੜϙΠϯτΛਐఄ͢Δ • ࣍Ͱɺ౷ܭใΛϝʔϧͰ୲ऀʹૹΓ͍ͨ • ΩϡʔΛॲཧ͢ΔʢCSV ΞοϓϩʔυͰେྔొͳͲʣ • ΞΫηεͷগͳ͍ਂʹΩϟογϡΛΫϦΞ͍ͨ͠ -
> < 45 JJUG CCC 2016 Spring. 2016/05/21 ػೳ։ൃΛ͢Δલʹόονʹ͍ͭͯߟ͍͑ͨ͜ͱʢ2ʣ δϣϒεέδϡʔϥΛݕ౼͢Δɻ
• JP1 ͷ༻͏ • ͓ۚͳ͍͠ɾɾɾ • Rundeck ͱ͔ Azkaban ͋ͨΓͷ OSS Λ͏ • ߏங͕ΊΜͲͦ͘͞͏ɾɾɾ • cron • όονͷཧ͕͍͠ • ݁ہ Web ΞϓϦͷΤϯυϙΠϯτʹΞΫηε͢Δ͚ͩͰ͠ΐʁ • AWS ͷ Lambda Scheduled Event Ͱࠓ෩ͷδϣϒཧͩͥʔ • ݁ہ Web ΞϓϦͷʢུ ͬͱ؆୯ʹόονΛॻ͖͍ͨ -
> < 46 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ1ʣ Spring ͳΒ TaskScheduler ͕͑Δɻ @SpringBootApplication @EnableScheduling public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } @Slf4j @Component public class SampleTask { @Scheduled(cron = "*/1 * * * * *") public void echo() { log.info("Do batch.. {}", new Date()); } } @Scheduled Ͱࢦఆ࣌ࠁʹॲཧΛ࣮ߦͰ͖Δɻ ࢦఆ࣌ࠁͷଞʹ͔ྃ࣌Βࢦఆ࣌ࠁޙʹىಈͱ͍ͬͨॻ͖ํͰ͖Δɻ -
> < 47 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ2ʣ 2016-04-24 15:18:20 INFO [pool-1-thread-1] SampleTask - Do batch.. Sun Apr 24 15:18:20 JST 2016 2016-04-24 15:18:21 INFO [pool-1-thread-1] SampleTask - Do batch.. Sun Apr 24 15:18:21 JST 2016 ؆୯ʂʂ ͱݴ͑ɺ࣮ۀͰ͏ͨΊʹɺ͏ͪΐͬͱ͠·͠ΐ͏ɻ • ෳεϨουͰಈ͘Α͏ʹ͢Δ • ಛఆͷαʔόͷΈͰಈ͘Α͏ʹ͢Δ • όονͷ։࢝ɾऴྃ࣌ʹϩάΛग़͢ʢ࣮ߦ࣌ؒͱ͔ʣ • αʔόఀࢭ࣌ʹͭ -
> < 48 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ3ʣ @SpringBootApplication @EnableScheduling public class Application implements SchedulingConfigurer { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.setScheduler(taskScheduler()); } @Bean(destroyMethod = "shutdown") public Executor taskScheduler() { ThreadPoolTaskScheduler threadPool = new ThreadPoolTaskScheduler(); threadPool.setPoolSize(5); // shutdown ࣌ʹ Task ͷྃΛͭʢ࠷େ10ؒʣ threadPool.setWaitForTasksToCompleteOnShutdown(true); threadPool.setAwaitTerminationSeconds(60 * 10); return threadPool; } } configureTasks ͷதͰɺExecutorService Λ࣮ͨ͠ΫϥεΛηοτ͢Δ Thread ͷΛ૿͢ αʔόఀࢭ࣌ʹͭΑ͏ʹ͢Δ Scheduling ͷΧελϚΠζɺ SchedulingConfigurer ΠϯλϑΣʔεΛ࣮͢Δ͜ͱͰ࣮ݱՄೳɻ -
> < 49 JJUG CCC 2016 Spring. 2016/05/21 @Slf4j @Aspect
@Component public class TaskInterceptor { @Value(“${batch.exec.host}”) String batchExecHost; @Around("execution(* com.example.task..*.*(..)) && @annotation(org.springframework.scheduling.annotation.Scheduled)") public Object around(ProceedingJoinPoint pjp) throws Throwable { String methodName = pjp.getSignature().getName(); String currentThread = Thread.currentThread().getName(); // ࣮ߦνΣοΫ if (!allowedBatchExec()) { log.info("Skip batch ({}): {}", currentThread, methodName); return null; } log.info("Begin batch ({}): {}", currentThread, methodName); Stopwatch stopWatch = Stopwatch.createStarted(); try { return pjp.proceed(); } catch (Exception e) { log.error("batch error: {}", methodName, e); return null; } finally { log.info("End batch ({}): {}, elapsed = {} (ms)", currentThread, methodName, stopWatch.elapsed(TimeUnit.MILLISECONDS)); } } private boolean allowedBatchExec() { if (getHostName().equals(batchExecHost)) { return true; } return false; } } AOP Ͱόονͷ࣮ߦ੍ޚΛ࣮ݱ͢Δ ಛఆͷϗετͰ͔͠ಈ͔ͳ͍Α͏ʹ͢Δ ։࢝ɾऴྃɾܭଌϩάΛग़͢ -
> < 50 JJUG CCC 2016 Spring. 2016/05/21 ·ͱΊ ɿ
όον όονॲཧ͕େྔʹ͋Δɺ όονॲཧ͕Ϗδωε্ɺ݁ߏॏཁɺͷཁ͕݅͋Δ߹ɺ Spring ͳΒ Spring Batch Quartz Λݕ౼͢Δͷ͋Γɻ ಛఆʹύοέʔδԼʹ @Scheduled Λ͚ͭͨϝιουΛ࣮͢Δ ͜ΕͰɺόονॲཧ ͱ͍͏ɺػೳ։ൃ Ready ͳঢ়ଶʹͳͬͨʂ -
> < 52 JJUG CCC 2016 Spring. 2016/05/21 ػೳ։ൃΛ͢ΔલʹϓϩύςΟʹ͍ͭͯߟ͍͑ͨ͜ͱ •
ຊ൪ڥ։ൃڥͳͲͰઃఆϑΝΠϧΛ͚͍ͨ • DB ͷଓઌΛม͍͑ͨ • ։ൃ࣌ messageSource ͷ cache ແ͠ʹ͍ͨ͠ͳͲ • ֎෦ʢOSڥมʣ͔ΒઃఆΛ্ॻ͖Ͱ͖ΔΑ͏ʹ͍ͨ͠ • application.properties όʔδϣϯཧରʹ͍ͯ͠Δ͕ɺ DB ͷύεϫʔυͷػີใଞͷਓ͔ΒݟΒΕͳ͍Α͏ʹ͍ͨ͠ɻ • Twelve-Factor App ͷཁૉͱͯ͠ॏཁ -
> < 53 JJUG CCC 2016 Spring. 2016/05/21 ຊ൪ڥ։ൃڥͳͲͰઃఆϑΝΠϧΛ͚͍ͨ Spring
Boot ͰɺProfile ͕͑Δɻ mvn spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=development" # application.properties, application-development.properties ͕ಡΈࠐ·ΕΔ mvn spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=test" # application.properties, application-test.properties ͕ಡΈࠐ·ΕΔ jar ͷ߹ɺ java -jar -Dspring.profiles.active=production hoge.jar -
> < 54 JJUG CCC 2016 Spring. 2016/05/21 ֎෦ʢOSڥมʣ͔ΒઃఆΛ্ॻ͖Ͱ͖ΔΑ͏ʹ͍ͨ͠ʢ1ʣ Spring
Boot ͰɺϓϩύςΟҎԼͷॱংͰಡΈࠐ·ΕΔʢ্ͷํ͕༏ઌʣ 1. Command line arguments. 2. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property) 3. ServletConfig init parameters. 4. ServletContext init parameters. 5. JNDI attributes from java:comp/env. 6. Java System properties (System.getProperties()). 7. OS environment variables. 8. A RandomValuePropertySource that only has properties in random.*. 9. Profile-specific application properties outside of your packaged jar (application- {profile}.properties and YAML variants) 10.Profile-specific application properties packaged inside your jar (application- {profile}.properties and YAML variants) 11.Application properties outside of your packaged jar (application.properties and YAML variants). 12.Application properties packaged inside your jar (application.properties and YAML variants). 13.@PropertySource annotations on your @Configuration classes. 14.Default properties (specified using SpringApplication.setDefaultProperties). -
> < 55 JJUG CCC 2016 Spring. 2016/05/21 ֎෦ʢOSڥมʣ͔ΒઃఆΛ্ॻ͖Ͱ͖ΔΑ͏ʹ͍ͨ͠ʢ2ʣ application-production.properties
spring.datasource.password="dummy" SPRING_DATASOURCE_PASSWORD="hogehoge" OS ڥม Spring Boot ͰɺRelaxed binding ͷػೳ͕͋ΔͷͰɺ্هͷมಉ͡ɻ Property Note person.firstName Standard camel case syntax. person.first-name Dashed notation, recommended for use in .properties and .yml files. PERSON_FIRST_NAME Upper case format. Recommended when using a system environment variables. http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot- features-external-config-relaxed-binding -
> < 56 JJUG CCC 2016 Spring. 2016/05/21 ·ͱΊ ɿ
ϓϩύςΟ ֤ڥผͷϓϩύςΟɺ֤ڥ༻ͷϑΝΠϧʹهड़͢Δ ͜ΕͰɺϓϩύςΟʹؔͯ͠ ͱ͍͏ɺػೳ։ൃ Ready ͳঢ়ଶʹͳͬͨʂ ػີใ OS ڥมͰ্ॻ͖ -
> < 58 JJUG CCC 2016 Spring. 2016/05/21 ػೳ։ൃΛ͢ΔલʹϩΪϯάʹ͍ͭͯߟ͍͑ͨ͜ͱ •
log4j ͍͍ՃݮʹΊ͍ͨ • ग़ྗจࣈྻͷߏஙͱ͔ΊΜͲ͍͘͞ • isDebugEnabled ΊΜͲ͍͘͞ • log4j طʹ EOL • ϩάΠϯ͍ͯ͠Δ userIdɺrequestId ࣗಈͰ͘Α͏ʹ͍ͨ͠ • ͜ΕΒΛϩάʹग़͓ͯ͘͠ͱɺো࣌ͷݪҼڀ໌ʹศརɻ ಛʹ requestId ʹؔͯ͠ microservices తʹ։ൃ͍ͯ͠Δ߹ɺ αʔϏεؒͷϩάͷඥ͚ͱͯ͠ಛʹॏཁɻ • ͨͩɺࣗͰຖճॻ͘ͷͩΔ͍ɻ -
> < 59 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ1ʣ log4j ͍͍ՃݮʹΊ͍ͨ Spring Boot ͳΒ SLF4J + logback ͕σϑΥϧτࡌɻ application.properties(.yml) Ͱઃఆมߋ͕Մೳ͕ͩɺ༰ݶΒΕΔɻ logback-spring.xmlʢlogback.xml Ͱͳ͘ʣΛ༻ҙ͠·͠ΐ͏ɻ logback-spring.xml ͱ͍͏ϑΝΠϧΛ༻ҙ͓ͯ͘͠ͱɺ Logback extensionsʢಠࣗλάʣ͕͑ΔͷͰศརɻ <springProfile name="!production"> <!-- configuration to be enabled when the "production" profile is not active --> </springProfile> <springProperty scope="context" name="fluentHost" source="myapp.fluentd.host" defaultValue="localhost"/> <appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender"> <remoteHost>${fluentHost}</remoteHost> ... </appender> -
> < 60 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ2ʣ ϩάΠϯ͍ͯ͠Δ userIdɺrequestId ࣗಈͰ͘Α͏ʹ͍ͨ͠ MDC = Mapped Diagnostic ContextʢϚοϓԽ͞ΕͨஅίϯςΩετʣ Thread Local ͳ Map ΛϩάͷՃใͱͯ͠ར༻Ͱ͖Δײ͡ɻ Map ʹઃఆ͞ΕͨͷɺࣗಈͰΫϦΞ͞Εͳ͍ͷͰɺ ͪΌΜͱࣗͰΫϦΞ͢Δඞཁ͕͋Δɻ Web ΞϓϦέʔγϣϯͷ߹ɺServlet Filter Ͱ࣮͞ΕΔ͜ͱ͕ଟ͍ɻ ͜͏͍͏࣌ MDC -
> < 61 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ3ʣ public class MDCLoggingFilter implements Filter { private static final String KEY_REQUEST_ID = "REQUEST_ID"; private static final String KEY_LOGIN_USER_ID = "LOGIN_USER_ID"; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { putMDC(request); try { chain.doFilter(request, response); } finally { clearMDC(); } } private void putMDC(ServletRequest request) { if (request instanceof HttpServletRequest) { HttpServletRequest httpRequest = (HttpServletRequest) request; String requestId = httpRequest.getHeader("X-Request-Id"); if (requestId != null) { MDC.put(KEY_REQUEST_ID, requestId); } String loginUserId = "t-yoshida"; // session ͔ΒϢʔβใΛऔಘ if (loginUserId != null) { MDC.put(KEY_LOGIN_USER_ID, loginUserId); } } } private void clearMDC() { MDC.remove(KEY_REQUEST_ID); MDC.remove(KEY_LOGIN_USER_ID); } // লུ } MDC ʹ put ͢Δ MDC ͔Β remove ͢Δ -
> < 62 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ4ʣ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{ISO8601} %-5p [%t] %c{2} \(%L\) - [%X{REQUEST_ID:-undefined}][%X{LOGIN_USER_ID:- undefined}] %m%n</pattern> </encoder> </appender> 2016-05-02 21:45:12,490 INFO [http-nio-8080-exec-4] c.e.c.s.a.LogController (14) - [ab939dfca5d57843ea4c695cab6f721d][t-yoshida] Log1 2016-05-02 21:45:12,491 INFO [http-nio-8080-exec-4] c.e.c.s.a.LogController (15) - [ab939dfca5d57843ea4c695cab6f721d][t-yoshida] Log2 @Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Bean public FilterRegistrationBean mdcLoggingFilter() { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new MDCLoggingFilter()); bean.setOrder(1); return bean; } } Filter Λొ͢Δ MDC ͷΛදࣔ͢Δ -
> < 63 JJUG CCC 2016 Spring. 2016/05/21 ·ͱΊ ɿ
ϩΪϯά SLF4J + logback ͕͑ͯɺuserId ࣗͰॻ͔ͳͯ͘Α͍ ͜ΕͰɺϩΪϯάʹؔͯ͠ ͱ͍͏ɺػೳ։ൃ Ready ͳঢ়ଶʹͳͬͨʂ -
> < 65 JJUG CCC 2016 Spring. 2016/05/21 ػೳ։ൃΛ͢ΔલʹηΩϡϦςΟʹ͍ͭͯߟ͍͑ͨ͜ͱ •
XSS • ςϯϓϨʔτΤϯδϯͰࣗಈͰΤεέʔϓ͞Ε͍ͯΔ͔ʁ • SQL Injection • OR ϚούʔͰదʹ Injection ରࡦ͕ͳ͞Ε͍ͯΔ͔ʁ • LIKE ԋࢉࢠ ORDER BY ۟ͷόΠϯυมͷڍಈ • CSRF • ࣗͰ࡞Γࠐ·ͣɺ؆୯ʹରࡦ͕Ͱ͖Δ͔ʁ • Http Security HeadersʢList of useful HTTP headers – OWASPʣ • ؆୯ʹઃఆͰ͖ΔͷͰɺ͓͖͍ͬͯͨɻ • ϥΠϒϥϦʢjarʣͷΞοϓσʔτ • pom.xml ͷ jar ͕શવߋ৽͞Εͳ͍ͱ͔ɾɾɾ ʢ˞ ೝূɾೝՄʹ͍ͭͯઆ໌͠·ͤΜʣ -
> < 66 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ1ʣ XSS Spring Boot ͳΒ Thymeleaf ͕Ұ൪͓͢͢Ίɻ Thymeleaf ʹΑΔςΩετͷग़ྗσϑΥϧτͰΤεέʔϓ͞ΕΔɻ <!-- Τεέʔϓ͞ΕΔ --> <span th:text=“${message}">escapedString</span> <!-- Τεέʔϓ͞Εͳ͍ --> <span th:utext="${message}">unescapedString</span> ͪΌΜͱ҆શଆ͕σϑΥϧτʹͳ͍ͬͯΔɻ -
> < 67 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ2ʣ SQL Injection ͪΌΜͱͨ͠ OR ϚούʔΛબͼ·͠ΐ͏ɻ ʢPrepared Statement ͰϓϨʔεϗϧμΛͪΌΜͱ͏ʣ ͱݴ͑ɺLIKE ԋࢉࢠ ORDER BY ۟ͷΤεέʔϓɺ ։ൃऀʹ͞Ε͍ͯΔ߹͕͋ΔͷͰɺ ೖྗจࣈྻΛ͖ͪΜͱόϦσʔγϣϯ͢Δɻ • ϗϫΠτϦετͰݕূ͢Δ • ϗϫΠτϦετ͕͑ͳ͍߹ɺϦςϥϧΛਖ਼͘͠Τεέʔϓ͢Δ -
> < 68 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ3ʣ CSRF Spring Security Λ͑ɺϑΥʔϜͷτʔΫϯຒΊࠐΈ͔Βɺ αʔόʔαΠυͰͷνΣοΫ·ͰΛࣗಈͰͬͯ͘ΕΔɻ ͨͩ͠ɺSpring Security ݁ߏ͓͔͍ͤͬͳͷ༗ޮʹͳͬͯ͠·͏ͷͰɺ ͦ͜ΒΜͪΌΜͱແޮԽ͠ͳ͍ͱ͍͚ͳ͍ɻBasic ೝূͱ͔ɻ <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies> security.basic.enabled=false -
> < 69 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ4ʣ ࡉ͔͍ઃఆɺapplication.properties ͔ɺ WebSecurityConfigurerAdapter Λܧঝͨ͠ΫϥεͰઃఆՄೳɻ @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // CSRF อޢΛແޮԽ͢Δ URL String[] ignoreCsrfPatterns = Stream.of(Site.values()) .filter(l -> !l.isProtectCsrf()).map(l -> l.getBaseUrl() + "/**").toArray(String[]::new); http.csrf() .ignoringAntMatchers(ignoreCsrfPatterns).and() // CSRF อޢΛແޮԽ͢Δ URL Λࢦఆ͢Δ .exceptionHandling().accessDeniedHandler(accessDeniedHandler); // CSRF ʹҾ͔͔ͬͬͬͨ߹ͷྫ֎ϋϯυϦϯά } @Value("${server.error.path:${error.path:/error}}") private String errorPath; private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandler() { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { if (!response.isCommitted()) { request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, accessDeniedException); response.setStatus(HttpStatus.FORBIDDEN.value()); request.getRequestDispatcher(errorPath).forward(request, response); } } }; } API CSRF อޢΛແޮԽ͢Δ CSRF ʹҾ͔ͬͬͨ߹ɺGlobalErrorController ʹ forward ͢ΔΑ͏ʹઃఆɻ -
> < 70 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ5ʣ ࣗಈͰઃఆ͞ΕΔ※ ʢth:action Λ͍ͬͯΔ߹ʣ -
> < 71 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ6ʣ Status Code 403 -
> < 72 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ7ʣ Http Security HeadersʢList of useful HTTP headers – OWASPʣ Spring Security Λ༗ޮʹ͢ΕɺSecurity Header ࣗಈͰ༩͞ΕΔɻ ࡉ͔͍ઃఆɺapplication.properties ͔ɺWebSecurityConfigurerAdapter Λ ܧঝͨ͠ΫϥεͰઃఆՄೳɻ spring.mvc.static-path-pattern=/public/** security.ignored=/public/** security.headers.cache=true # Enable cache control HTTP headers. security.headers.content-type=true # Enable "X-Content-Type-Options" header. security.headers.frame=true # Enable "X-Frame-Options" header. security.headers.hsts= # HTTP Strict Transport Security (HSTS) mode (none, domain, all). security.headers.xss=true # Enable cross site scripting (XSS) protection. security.ignored= # Comma-separated list of paths to exclude from the default secured paths. σϑΥϧτ Static Resource আ֎ https://www.owasp.org/index.php/List_of_useful_HTTP_headers -
> < 73 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ8ʣ Security Header ͕ ग़ྗ͞Ε͍ͯΔ -
> < 74 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ9ʣ ϥΠϒϥϦʢjarʣͷΞοϓσʔτ Spring Boot ͷ߹ɺspring-boot-starter-parent ͷ POM ͕ɺ ߹ੑͷऔΕͨˍΘΓͱ࠷৽ͷ jar Λͬͯ͘ΕΔͷͰɺ جຊతʹ Boot ͷόʔδϣϯΛ্͛Δ͚ͩʢࣗͰ <version> Λࢦఆ͠ͳ͍ʣ ͨͩ͠ɺݸผͷ jar Ͱ Security Fix ͳͲ͕ग़ͯɺ Boot ͷϦϦʔε͕ؒʹ߹͍ͬͯͳ͍߹ɺݸผʹόʔδϣϯΛࢦఆ͢Δɻ <properties> <jedis.version>2.8.1</jedis.version> </properties> POM Ͱ property ͕ΘΕ͍ͯΔͷͰɺ ͦΕΛ্ॻ͖͢Δ͚ͩͰΑ͍ɻ https://github.com/spring-projects/spring-boot/blob/master/spring-boot- dependencies/pom.xml -
> < 75 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ10ʣ ࣗͰೖΕͨ jar ͷ߹ɺVersions Maven Plugin Λ͏ͷ͕ศརɻ http://www.mojohaus.org/versions-maven-plugin/ <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>versions-maven-plugin</artifactId> <version>2.1</version> </plugin> </plugins> </build> όʔδϣϯΞοϓ͕Մೳͳ dependency, plugin ͷදࣔߋ৽ʢةݥʂʣ Λߦ͏͜ͱ͕Ͱ͖Δɻ ଞʹ project ͷ <version> λάͷߋ৽ͳͲͰ͖Δɻ -
> < 76 JJUG CCC 2016 Spring. 2016/05/21 Ͱ Spring
Boot ͰͲ͏͢Δ͔ʁʢ11ʣ [SpringDemo] mvn versions:display-dependency-updates [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building SpringDemo 0.0.1-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- versions-maven-plugin:2.1:display-dependency-updates (default-cli) @ SpringDemo --- [INFO] The following dependencies in Dependency Management have newer versions: [INFO] antlr:antlr ........................................ 2.7.7 -> 20030911 [INFO] ch.qos.logback:logback-access ......................... 1.1.5 -> 1.1.7 [INFO] ch.qos.logback:logback-classic ........................ 1.1.5 -> 1.1.7 [INFO] com.atomikos:transactions-jdbc ........................ 3.9.3 -> 4.0.2 [INFO] com.atomikos:transactions-jms ......................... 3.9.3 -> 4.0.2 [INFO] com.atomikos:transactions-jta ......................... 3.9.3 -> 4.0.2 ... [INFO] [INFO] The following dependencies in Dependencies have newer versions: [INFO] org.mybatis.spring.boot:mybatis-spring-boot-starter ... 1.0.2 -> 1.1.1 [INFO] org.projectlombok:lombok ............................ 1.16.6 -> 1.16.8 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.462 s [INFO] Finished at: 2016-05-04T11:37:18+09:00 [INFO] Final Memory: 9M/205M [INFO] ------------------------------------------------------------------------ POM Ͱࢦఆ͞ΕͯΔ jar ͷόʔδϣϯใ όʔδϣϯΞοϓ͕Մೳͳ dependency Λදࣔ͢Δ mvn ίϚϯυ ࣗͰೖΕͨ jar ͷόʔδϣϯใ ߋ৽͠·͠ΐ͏ -
> < 77 JJUG CCC 2016 Spring. 2016/05/21 ·ͱΊ ɿ
ηΩϡϦςΟ XSS ΞϯΤεέʔϓͯ͠ग़ྗ͍͚ͨ࣌ͩ͠ҙ͢Δ ͜ΕͰɺηΩϡϦςΟʹؔͯ͠ ͱ͍͏ɺػೳ։ൃ Ready ͳঢ়ଶʹͳͬͨʂ SQL Injection όΠϯυมΛΘͳ͍͚࣌ͩҙ͢Δ CSRF ࣗಈͰରࡦ͞ΕΔΑ͏ʹͳͬͨʢth:action Εͣʹʣ Boot ͷ version Λҙࣝͭͭ͠ɺఆظతʹόʔδϣϯΞοϓΛ֬ೝ Http Security Headers ࣗಈͰग़ྗ -
> < 79 JJUG CCC 2016 Spring. 2016/05/21 DevTools ։ൃ࣌ʹେମઃఆ͢ΔͰ͋Ζ͏ɺ
ςϯϓϨʔτΩϟογϡͷແޮԽɺϗοτϦϩʔυͷઃఆ͕ҰൃͰՄೳɻ ʢSpring Loaded ͱผʣ <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> </dependencies> http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/ #using-boot-devtools ͜ͷઃఆ͚ͩͰ spring.thymeleaf.cache=false ͱ͔ɺ spring.freemarker.cache=false Λɺݸผʹॻ͔ͳͯ͘Α͘ͳΔɻ ͪΖΜຊ൪ڥͰ༗ޮʹͳΒͳ͍Α͏ʹߟྀ͞Ε͍ͯΔɻ -
> < 80 JJUG CCC 2016 Spring. 2016/05/21 lombok Spring
ؔͳ͍͚Ͳɺ͍͢͝ศརͳͷͰɺੋඇಋೖ͠·͠ΐ͏ɻ ͨͩ͠ɺexperimental ͳػೳʹ͍ͭͯɺ͝ར༻ܭըతʹɻ <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.8</version> <scope>provided</scope> </dependency> </dependencies> -
> < 81 JJUG CCC 2016 Spring. 2016/05/21 ΞϓϦέʔγϣϯͷݟ͑ΔԽ Spring
ΞϓϦέʔγϣϯͰɺ৭ʑͳͷΛݟ͑ΔԽ͓ͯ͘͠ͱɺ ΞϓϦέʔγϣϯͷཧղ͕ਂ·ͬͨΓɺࡉ͔ͳϛεΛؾ͚ͮΔɻ Spring ࣗମͷཧղḿΔɻ • Routing • Context • Batch • Build Info ʢͦΕɺactuator ͰͰ͖ΔΑʣ -
> < 82 JJUG CCC 2016 Spring. 2016/05/21 ΞϓϦέʔγϣϯͷݟ͑ΔԽʢRoutingʣ https://github.com/sinsengumi/spring-boot-application-infrastructure/blob/
master/src/main/java/com/example/controller/screen/admin/system/ RouterController.java -
> < 83 JJUG CCC 2016 Spring. 2016/05/21 ΞϓϦέʔγϣϯͷݟ͑ΔԽʢContextʣ https://github.com/sinsengumi/spring-boot-application-infrastructure/blob/
master/src/main/java/com/example/controller/screen/admin/system/ ContextController.java -
> < 84 JJUG CCC 2016 Spring. 2016/05/21 ΞϓϦέʔγϣϯͷݟ͑ΔԽʢBatchʣ https://github.com/sinsengumi/spring-boot-application-infrastructure/blob/
master/src/main/java/com/example/controller/screen/admin/system/ BatchController.java -
> < 85 JJUG CCC 2016 Spring. 2016/05/21 ΞϓϦέʔγϣϯͷݟ͑ΔԽʢBuild Infoʣ
https://github.com/sinsengumi/spring-boot-application-infrastructure/blob/ master/src/main/java/com/example/controller/screen/admin/system/ BuildController.java -
> < 87 JJUG CCC 2016 Spring. 2016/05/21 ·ͱΊ •
ػೳΛ࡞ΓࠐΉલʹɺج൫ઃܭΛͪΌΜͱ͓ͯ͜͠͏ • Έ߹Θ͕ͤେมͱ͔ݴ͚ͬͨͲɺSpring Boot ૉΒ͍͠ϓϩμΫτ ࠓɺJava ͰΞϓϦ࡞ΔͳΒɺީิͱͯ͠࠷༗ྗͳͣ • ࠓͤͳ͔ͬͨ͜ͱʢೝূɾೝՄɺΩϟογϡɺςετʣ • ࠓͷαϯϓϧίʔυ https://github.com/sinsengumi/spring-boot-application-infrastructure