2022. 3. 28. 17:14ใBack-End ์์ ์ค/Spring Framework

๐ @Valid
๐ฝ ๊ฐ์
Spring์ ์ด์ฉํ์ฌ `Controller`๋ฅผ ๋ง๋ค๊ณ , ๊ฒ์ํ, ํ์ ๊ฐ์ ๋ฑ Client์์ ์ ๋ ฅ๊ฐ์ ๋ฐ์ ๋๋ ํญ์ ์ ํจ์ฑ ๊ฒ์ฌ(Validation)์ ํด์ผ ํ๋ ๊ฒ์ด์์.
์ด ์ ํจ์ฑ ๊ฒ์ฌ๋ Client (Front End)์์๋ ํด์ผ ํ์ง๋ง, Server (Back End)์์๋ ๊ผญ ์งํ์ ํด์ค์ผ ํ๋๋ฐ, ๊ทธ ์ด์ ๋ ์ ์์ ์ธ ์ด์ฉ์๊ฐ ์ฐํ ๋ฐฉ๋ฒ์ ํตํด Server์๊ฒ ์ ๋ ฅ๊ฐ์ ์ ๋ ฅํ๋ ค๋ ์๋๋ฅผ ํตํด Client์ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ๋ฌด๋ ฅํ ์ํฌ ์ ์๊ธฐ ๋๋ฌธ์ธ ๊ฒ์ด์์.
์ด๋ฅผ ํตํด `SQL Injection`, `XSS(Cross Site Scripting)` ๋ฑ์ ๊ณต๊ฒฉ ๋ฐฉ์ด๋ฅผ ์ํด ๊ผญ! ์ ๋ ฅ๊ฐ์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ค์ํด์ฃผ์ด ์๋ํ์ง ์์ ๊ฐ์ด ๋ค์ด์ค์ง ์๊ฒ ๋ฐฉ์ด ํด์ค์ผ ํ๋ ๊ฒ์ด์์.
`@Valid`๋ฅผ ์ด์ฉํ๋ฉด `Service` ๋จ์ด ์๋ ๊ฐ์ฒด(Entity, VO, DTO)์์์ Client์์ ๋ค์ด์ค๋ ๊ฐ์ ๋ํด ๊ฒ์ฆ์ ํ ์ ์๋ ๊ฒ์ด์์.
`Jakarata Bean Validation API Packages`์ ์๋ `javax.validation.constraints` Package์ ์๋ ๊ธฐ๋ณธ์ ์ธ ๊ฒ์ฆ Annotaion์ ์ด์ฉํ ๊ฒ์ด์์.
`javax.validation.constraints`Package ์์๋ ์์ฃผ ๋ง์ Annotaion์ด ์กด์ฌํ๋๋ฐ, `@Valid`๋ฅผ ์ด์ฉํ ๊ฐ์ฒด ๊ฒ์ฆ ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ด Annotaion์ ์ด์ฉํ๋ต๋๋ค.
๐ก ์ฐธ๊ณ ์ฌํญ
`SpringBoot`๊ฐ Version Update๋ฅผ ํ๋ฉด์ `web` ์์กด์ฑ ์์ ์๋ `constraints package`๊ฐ ์์ Module๋ก ๋น ์ง
๐ฝ ์์กด์ฑ ์ถ๊ฐ
๐ฆ Maven

๐ฆ Gradle

๐ฝ @Valid ์ฌ์ฉ

์์ ๊ทธ๋ฆผ์ ๋ณด๋ฉด 50๋ฒ์งธ ์ค ๋งค๊ฐ๋ณ์ ์
๋ ฅ๋์ `@Valid`๋ฅผ ์ ์ธํ ๊ฒ์ ๋ณผ ์ ์๋ ๊ฒ์ด์์.
์ด๋ ๊ฒ ํ๋ฉด RequestBody๋ก ๋ค์ด์ค๋ ๊ฐ์ฒด์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ค์ํ๋ผ๊ณ ์ง์๋ฅผ ๋ด๋ ค์ค ๊ฒ์ด์์.
์ด๋ค ๊ฒ์ ๊ฒ์ฌ๋ฅผ ํ ๊ฒ์ธ์ง๋ Entity, VO, DTO ๋ฑ์ ์์ฑ์ ํด ์ฃผ์ด์ผ ํฉ๋๋ค!

์ฃผ๋ํ๋์ ์ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด DTO ๊ฐ์ฒด๋ฅผ ์ ์ํ๊ณ , username(ID) ํ๋์ ์ด๋ป๊ฒ ๊ฐ์ ๋ฐ์์ง์ ๋ํด ์ ์ํด ์ค ๊ฒ์ด์์.
โ @NotBlank : Null์ด ์๋ ๊ฐ๋ง ํ์ฉํ๋ฉฐ, ๊ณต๋ฐฑ์ด ์๋ ๋ฌธ์ ํ๋ ์ด์์ ํฌํจํด์ผ ํ์ฉํ๋ค.
โ @Size(min = x, max = x) : min ๋ณด๋ค ํฌ๊ฑฐ๋, ๊ฐ๊ณ , max ๋ณด๋ค ์๊ฑฐ๋, ๊ฐ์ ๋ฌธ์์ด ๊ธธ์ด ๋ด์ ๊ฐ๋ง ์์ฉํ๋ค.
โ @Pattern(regex = xxx) : regex์ ์
๋ ฅ๋ ์ ๊ท ํํ์์ ๋ง๋ ๊ฐ๋ง ์
๋ ฅ ํ์ฉํ๋ค.

์ผ๋จ ์์ ๊ฐ์ด ํ์ฉ๋ ๊ฐ์ ๋ฃ์ด์ ์์ฒญ์ ๋ณด๋ด๊ฒ ๋๋ฉด ํ์ฉ์ด ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ ๊ฒ์ด์์.

{
"timestamp": 1648444363174,
"status": 400,
"error": "Bad Request",
"trace": "org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.devcommunity.junyharang.common.constant.DefaultResponse com.devcommunity.junyharang.controller.member.UserController.duplicateUserID(com.devcommunity.junyharang.model.dto.user.DuplicateByUserIDDTO) with 2 errors: [Field error in object 'duplicateByUserIDDTO' on field 'username': rejected value [ ]; codes [NotBlank.duplicateByUserIDDTO.username,NotBlank.username,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [duplicateByUserIDDTO.username,username]; arguments []; default message [username]]; default message [๊ณต๋ฐฑ์ผ ์ ์์ต๋๋ค]] [Field error in object 'duplicateByUserIDDTO' on field 'username': rejected value [ ]; codes [Pattern.duplicateByUserIDDTO.username,Pattern.username,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [duplicateByUserIDDTO.username,username]; arguments []; default message [username],[Ljavax.validation.constraints.Pattern$Flag;@3bf02bec,^[0-9a-zA-Z]+$]; default message [\"^[0-9a-zA-Z]+$\"์ ์ผ์นํด์ผ ํฉ๋๋ค]] \n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:141)\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:681)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)\n\tat org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)\n\tat org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)\n\tat org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)\n\tat org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)\n\tat org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)\n\tat org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)\n\tat org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)\n\tat org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)\n\tat org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)\n\tat org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:359)\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889)\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1735)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tat java.base/java.lang.Thread.run(Thread.java:829)\n",
"message": "Validation failed for object='duplicateByUserIDDTO'. Error count: 2",
"errors": [
{
"codes": [
"NotBlank.duplicateByUserIDDTO.username",
"NotBlank.username",
"NotBlank.java.lang.String",
"NotBlank"
],
"arguments": [
{
"codes": [
"duplicateByUserIDDTO.username",
"username"
],
"arguments": null,
"defaultMessage": "username",
"code": "username"
}
],
"defaultMessage": "๊ณต๋ฐฑ์ผ ์ ์์ต๋๋ค",
"objectName": "duplicateByUserIDDTO",
"field": "username",
"rejectedValue": " ",
"bindingFailure": false,
"code": "NotBlank"
},
{
"codes": [
"Pattern.duplicateByUserIDDTO.username",
"Pattern.username",
"Pattern.java.lang.String",
"Pattern"
],
"arguments": [
{
"codes": [
"duplicateByUserIDDTO.username",
"username"
],
"arguments": null,
"defaultMessage": "username",
"code": "username"
},
[],
{
"arguments": null,
"defaultMessage": "^[0-9a-zA-Z]+$",
"codes": [
"^[0-9a-zA-Z]+$"
]
}
],
"defaultMessage": "\"^[0-9a-zA-Z]+$\"์ ์ผ์นํด์ผ ํฉ๋๋ค",
"objectName": "duplicateByUserIDDTO",
"field": "username",
"rejectedValue": " ",
"bindingFailure": false,
"code": "Pattern"
}
],
"path": "/api/user/duplicate/userid"
}
์ ๊ทธ๋ฆผ์ ๊ณต๋ฐฑ์ ์ ๋ ฅ ํ์ ๋ ๋ชจ์ต์ธ ๊ฒ์ด์์.

{
"timestamp": 1648444453061,
"status": 400,
"error": "Bad Request",
"trace": "org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.devcommunity.junyharang.common.constant.DefaultResponse com.devcommunity.junyharang.controller.member.UserController.duplicateUserID(com.devcommunity.junyharang.model.dto.user.DuplicateByUserIDDTO): [Field error in object 'duplicateByUserIDDTO' on field 'username': rejected value [#$%junyharang]; codes [Pattern.duplicateByUserIDDTO.username,Pattern.username,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [duplicateByUserIDDTO.username,username]; arguments []; default message [username],[Ljavax.validation.constraints.Pattern$Flag;@3bf02bec,^[0-9a-zA-Z]+$]; default message [\"^[0-9a-zA-Z]+$\"์ ์ผ์นํด์ผ ํฉ๋๋ค]] \n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:141)\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:681)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)\n\tat org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)\n\tat org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)\n\tat org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)\n\tat org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)\n\tat org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)\n\tat org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)\n\tat org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\n\tat org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)\n\tat org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)\n\tat org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)\n\tat org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)\n\tat org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:359)\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889)\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1735)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tat java.base/java.lang.Thread.run(Thread.java:829)\n",
"message": "Validation failed for object='duplicateByUserIDDTO'. Error count: 1",
"errors": [
{
"codes": [
"Pattern.duplicateByUserIDDTO.username",
"Pattern.username",
"Pattern.java.lang.String",
"Pattern"
],
"arguments": [
{
"codes": [
"duplicateByUserIDDTO.username",
"username"
],
"arguments": null,
"defaultMessage": "username",
"code": "username"
},
[],
{
"arguments": null,
"defaultMessage": "^[0-9a-zA-Z]+$",
"codes": [
"^[0-9a-zA-Z]+$"
]
}
],
"defaultMessage": "\"^[0-9a-zA-Z]+$\"์ ์ผ์นํด์ผ ํฉ๋๋ค",
"objectName": "duplicateByUserIDDTO",
"field": "username",
"rejectedValue": "#$%junyharang",
"bindingFailure": false,
"code": "Pattern"
}
],
"path": "/api/user/duplicate/userid"
}
์ด๋ ๊ฒ ์ ํด ๋์ ๊ท์น์ ๋ง์ง ์๋ ์ ๋ ฅ๊ฐ์ด ๋์ค๋ฉด HTTP Status Code 400(Bad Request - ๋์ ์์ฒญ)์ด๋ผ๊ณ ์๋ ค์ฃผ๋ฉด์ ์ ๋ ฅ์ ๋ฐ์ง ์๋ ๊ฒ์ ๋ณผ ์ ์๋ ๊ฒ์ด์์.
์ง๊ธ ์์์ ๋ณด์ด๋ `Response` ๋ด์ฉ์ `Spring`์ด ์๋์ผ๋ก ์ผ์ ๊ท๊ฒฉ์ ๋ง์ถฐ ์์ฑํ `Exception` ํ์ ๋ง์ถฐ ์๋ต์ ํด์ฃผ๋ ๊ฒ์ด์์.
๋ฐ.๋ผ.์ `@Valid`์ ๊ฒ์ฆ Annotaion๋ง ์ ์จ์ค๋ค๋ฉด ์ ๋ ฅ๊ฐ์ ๋ํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค๋ ๊ฒ์ด์์.
๐ฝ ๊ฒ์ฆ์ฉ Annotaion
๐ฆ ๋ฌธ์์ด ์ ๋ฌด ๊ฒ์ฆ(@NotBlank, @NotEmpty, @NotNull)
| ์ข ๋ฅ | null ํ์ฉ ์ฌ๋ถ |
"" ํ์ฉ ์ฌ๋ถ |
" " ํ์ฉ ์ฌ๋ถ |
๋ด ์ฉ |
| @NotNull | ํ์ฉ ์ํจ | ํ์ฉ | ํ์ฉ | - type : ์ด๋ค Type์ด๋ ํ์ฉ. - null์ด ์๋ ๊ฐ๋ง ํ์ฉ. -๋ฐ๋์ ๊ฐ์ด ์กด์ฌํด์ผ ํ๋ค. |
| @NotEmpty | ํ์ฉ ์ํจ | ํ์ฉ ์ํจ | ํ์ฉ | - type : CharSequence(length of character) Collection (collection size) Map (map size Array (array length) - null์ด๊ฑฐ๋, empty(๋น ๋ฌธ์์ด)์ด ์๋์ด์ผ ํ์ฉ. - ๋ฐ๋์ ๊ฐ์ด ์กด์ฌํด์ผ ํ๊ณ , ๊ธธ์ด ํน์ ํฌ๊ธฐ๊ฐ 0๋ณด๋ค ์ปค์ผ ํ๋ค. |
| @NotBlank | ํ์ฉ ์ํจ | ํ์ฉ ์ํจ | ํ์ฉ ์ํจ | - null์ด ์๋ ๊ฐ๋ง ํ์ฉ. - ๊ณต๋ฐฑ์ด ์๋ ๋ฌธ์ ํ๋ ์ด์ ํฌํจํด์ผ ํ์ฉ. - ๋ฐ๋์ ๊ฐ์ด ์กด์ ํ๊ณ , ๊ณต๋ฐฑ ๋ฌธ์๋ฅผ ์ ์ธํ ๊ธธ์ด๊ฐ 0๋ณด๋ค ์ปค์ผ ํ๋ค. |
๐ฆ ์ต๋ ์ต์์ ๋ํ ๊ฒ์ฆ
SupportType
โ BigDecimal, BitInteger, CharSequence byte, short, int, long์ ๋์ํ๋ Wrapper Class.
โ double, float๋ rounding Error๋ก ์ธํด ๋ฏธ์ง์.
โ null ๋ํ ํ์ฉ์ผ๋ก ๊ฐ์ฃผ.
์์ ์ฝ๋

๐ฆ ๋ฒ์ ๊ฐ์ ๋ํ ๊ฒ์ฆ
SupportType
โ BigDecimal, BitInteger, CharSequence byte, short, int, long, double, float์ ๋์ํ๋ Wrapper Class.
โ null ๋ํ ํ์ฉ์ผ๋ก ๊ฐ์ฃผ.
| ์ข ๋ฅ | ๋ด ์ฉ |
| @Posive | ์์์ธ ๊ฐ๋ง ํ์ฉ. |
| @PosiveOrZero | 0์ด๊ฑฐ๋, ์์์ธ ๊ฐ๋ง ํ์ฉ. |
| @Negative | ์์์ธ ๊ฐ๋ง ํ์ฉ. |
| @NegativeOrZero | 0์ด๊ฑฐ๋, ์์์ธ ๊ฐ๋ง ํ์ฉ. |
์์ ์ฝ๋

๐ฆ ์๊ฐ ๊ฐ์ ๋ํ ๊ฒ์ฆ
SupportType
โ java.util.Date, java.util.Calendar, java.time.instant, java.time.LocalDate, java.time.LocalDateTime, java.time.LocalTime, java.time.MonthDay, java.time.OffsetDateTime, java.time.OffsetTime, java.time.Year, java.time.YearMonty, java.time.ZonedDateTime, java.time.chrono.HijrahDate, java.time.chrono.JapaneseDate java.time.chrono.MinguoDate, java.time.chrono.ThaiBuddhistDate
โ null ๋ํ ํ์ฉ์ผ๋ก ๊ฐ์ฃผ.
`Now`์ ๊ธฐ์ค
`ClockProvider`์ `Virtual Machine`์ ๋ฐ๋ผ ํ์ฌ ์๊ฐ์ ์ ์. ํ์ํ ๊ฒฝ์ฐ `default time zone`์ ์ ์ฉ.
์์ ์ฝ๋

๐ฆ Email ๊ฒ์ฆ
SupportType
โ null ๋ํ ํ์ฉ์ผ๋ก ๊ฐ์ฃผ.
Validation
โ @Email : ์ฌ๋ฐ๋ฅธ ํ์์ Email ์ฃผ์์ฌ์ผ ํ๋ฉฐ, (`@`๊ฐ ๊ผญ ๋ค์ด๊ฐ์ผํ๊ณ , Domain์ '.'๋ ๊ฒ์ฌํ์ง ์์)
์์ ์ฝ๋

๐ฆ ์๋ฆฟ์ ๊ฒ์ฆ
SupportType
โ BigDecimal, BigInteger, CharSequence byte, short, int, long์ ๋์ํ๋ Wrapper Class.
โ null๋ ํ์ฉ์ผ๋ก ๊ฐ์ฃผ
Validation
โ @Digits : ํ์ฉ๋ ๋ฒ์ ๋ด ์ซ์๊ฐ
- Require : int integer = ์ด ์ซ์์ ํ์ฉ๋๋ ์ต๋ ์ ์ ์๋ฆฟ์
- Require : int fraction = ์ด ์ซ์์ ํ์ฉ๋๋ ์ต๋ ์์ ์๋ฆฟ์
์์ ์ฝ๋

๐ฆ ์ฐธ๊ณผ ๊ฑฐ์ง(Boolean) ๊ฒ์ฆ
SupportType
โ Boolean, boolean
Validation
| ์ข ๋ฅ | ๋ด ์ฉ |
| @AssertTure | ๊ฐ์ด ํญ์ `Ture`๋ง ํ์ฉ |
| @AssertFalse | ๊ฐ์ด ํญ์ `False`๋ง ํ์ฉ |
์์ ์ฝ๋

๐ฆ ํฌ๊ธฐ ๊ฒ์ฆ
SupportType
โ CharSequence (length of character sequence), Collection (collection size), Map (map size), Array(array length)
โ null๋ ํ์ฉ์ผ๋ก ๊ฐ์ฃผ
Validation
| ์ข ๋ฅ | ๋ด ์ฉ | Option |
| @Size | ์ด ํฌ๊ธฐ๊ฐ ์ง์ ๋ ๊ฒฝ๊ณ(ํฌํจ) ์ฌ์ด์ ์๋ ๊ฐ๋ง ํ์ฉ | int max : element์ ํฌ๊ธฐ๊ฐ ์๊ฑฐ๋ ๊ฐ๋ค. int min : element์ ํฌ๊ธฐ๊ฐ ํฌ๊ฑฐ๋ ๊ฐ๋ค. |
์์ ์ฝ๋

๐ฆ ์ ๊ท์ ๊ฒ์ฆ
SupportType
โ CharSequence
โ null๋ ํ์ฉ์ผ๋ก ๊ฐ์ฃผ
Validation
| ์ข ๋ฅ | ๋ด ์ฉ | Option |
| @Pattern | ์ง์ ํ ์ ๊ท์๊ณผ ๋์๋๋ ๋ฌธ์์ด๋ง ํ์ฉ. JAVA์ Pattern Package์ Convention์ ๋ฐ๋ฆ. |
String regxp : ์ ๊ท์ ๋ฌธ์์ด ์ง์ . |
์์ ์ฝ๋

๐ฆ ๊ทธ ๋ฐ์ @Valid ์ ๋ฆฌ
| ์ข ๋ฅ | ์ง์ Type | ๋ด ์ฉ |
| @Future | Time Class | Now ๋ณด๋ค ๋ฏธ๋์ ๋ ์ง์ ์๊ฐ๋ง ํ์ฉ. |
| @FutureOrPresent | Time Class | Now์ ์๊ฐ์ด๊ฑฐ๋, ๋ฏธ๋์ ๋ ์ง, ์๊ฐ๋ง ํ์ฉ. |
| @Past | Time Class | Now๋ณด๋ค ๊ณผ๊ฑฐ์ ๋ ์ง, ์๊ฐ๋ง ํ์ฉ. |
| @PastOrPrensent | Time Class | Now์ ์๊ฐ์ด๊ฑฐ๋, ๊ณผ๊ฑฐ์ ๋ ์ง, ์๊ฐ๋ง ํ์ฉ. |
๐ @Valid Exception Handling
์ฐ๋ฆฌ๋ ๋ฐ๋ก ์์์ `Spring`์ด ์ค์ค๋ก ๋ง๋ค์ด์ ๊ท์น์ ๋ง์ง ์์์ ๋, Exception์ ๋์ง๋ ๋ชจ์ต์ ๋ณธ ๊ฒ์ด์์.
๊ทผ๋ฐ, ๋๋ฌด ๊ธธ๊ณ , ๋ณต์กํ ๊ฒ์ด ๋๋ฌด ๋ง์์ ๋ค์ง ์๋ ๊ฒ์ด์์. ์ด๋ด ๋, ๊ฐ๋ฐ์๋ ๊ฐ๋ฐ์๊ฐ ์ํ๋ Exception์ ๋์ง ์ ์๋๋ก `Exception Handling`์ ํด ์ค ์ ์๋ต๋๋ค.
2022-03-28 14:12:43.166 WARN 3432 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.devcommunity.junyharang.common.constant.DefaultResponse com.devcommunity.junyharang.controller.member.UserController.duplicateUserID(com.devcommunity.junyharang.model.dto.user.DuplicateByUserIDDTO) with 2 errors: [Field error in object 'duplicateByUserIDDTO' on field 'username': rejected value [ ]; codes [NotBlank.duplicateByUserIDDTO.username,NotBlank.username,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [duplicateByUserIDDTO.username,username]; arguments []; default message [username]]; default message [๊ณต๋ฐฑ์ผ ์ ์์ต๋๋ค]] [Field error in object 'duplicateByUserIDDTO' on field 'username': rejected value [ ]; codes [Pattern.duplicateByUserIDDTO.username,Pattern.username,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [duplicateByUserIDDTO.username,username]; arguments []; default message [username],[Ljavax.validation.constraints.Pattern$Flag;@3bf02bec,^[0-9a-zA-Z]+$]; default message ["^[0-9a-zA-Z]+$"์ ์ผ์นํด์ผ ํฉ๋๋ค]] ]
์๋ชป๋ ์ ๋ ฅ๊ฐ์ด ๋ค์ด์์ ๋, ์์ ๊ฐ์ด `MethodArgumentNotValidException`์ด ๋ฐ์ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ ๊ฒ์ด์์. ์ด๊ฒ์ ์ด์ฉํ์ฌ Custom ํ๊ฒ Exception์ ์ฒ๋ฆฌํ ์ ์๋ต๋๋ค.
์ด Exception์ Handling ํ๊ณ ์ ํ๋ `Controller`์์ ์ ์ํด๋ ๋์ง๋ง, ์ฃผ๋ํ๋์ ์ ์ญ์ ์ฌ์ฉ์ ์ํด ์๋์ ๊ฐ์ด `@ControllerAdvice`๋ฅผ ์ ์ํด์ ์ด์ฉํ ๊ฒ์ด์์.

๋จผ์ ๋งค๊ฐ๋ณ์๋ก`MethodArgumentNotValidException`์ ๋ฐ์ `@Valid`์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ์คํจ ํ์ ๋, ํด๋น Method๊ฐ ํธ์ถ๋๊ฒ ํ ๊ฒ์ด์์.
`BindingResult`์ `FiedError`์์ ๊ฒ์ฆ์ด ์คํจํ Field ์ด๋ฆ(Member ๋ณ์ ์ด๋ฆ), ์คํจ์ ๋ํ Message, ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ ์คํจํ ์ ๋ ฅ๊ฐ์ ๊ฐ์ ธ์ ์ถ๋ ฅ๋ Message๋ฅผ ๋ง๋ค์ด ์ฃผ๊ณ ์๋ ๊ฒ์ด์์.
๊ทธ๋ฆฌ๊ณ ๋์ `Return Type`์ ๋ณด๋ฉด `ResponseEntity<DefaultResponse<String>>`์ผ๋ก ํด ๋์๋๋ฐ,

์ฃผ๋ํ๋์ ์๋ต(Reponse)๊ฐ ๋๊ฐ ๋, ๋ณด๋ค ์ ๊ฐํ๊ณ , ํธ๋ฆฌํ๊ฒ ์๋ต์ ๋ณด๋ด๊ธฐ ์ํด ์์ ๊ฐ์ Class ํ๋๋ฅผ ๋ฏธ๋ฆฌ ๋ง๋ค์ด ๋ ๊ฒ์ด์์. ์ด๊ฒ์ ๋ง์ถ์ด ์๋ต๊ฐ์ ๋ณด๋ด๊ฒ ํ๊ธฐ ์ํด Return Type์ ์์ ๊ฐ์ด ํด ์ค ๊ฒ์ด๋๋๋ค.
`ExceptionAdvisor.java`์ return๋ฌธ์ ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ฒ์์ HTTP Status Code (400)์ value(Bad Request)๋ฅผ ์ ๋ ฅ๋๊ฒ ํด ์ฃผ์๊ณ , ํ๊ธ๋ก ๋ฌด์จ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋์ง ์๋ ค์ฃผ๊ฒ ์ ๋ ฅ์ ํด ์ฃผ๊ณ , ๋ฌธ์ ์ ๋ํ ์์ธ ๋ด์ฉ์ด ์ถ๋ ฅ๋๊ฒ ํด์ฃผ๊ณ , Http Status Code 400์ ์ ๋ ฅํด ์ฃผ์ด Exception์ด ๋๊ฐ ์ ์๊ฒ ํด ์ค ๊ฒ์ด์์.
์ด๋ ๊ฒ ํด์ ๋ค์ ํ๋ฆฐ ์์ฒญ์ ๋ณด๋ด๊ฒ ๋๋ฉด ์๋์ ๊ฐ์ด ์ ๋ฆฌ๋ Exception์ด ์๋ต๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ต๋๋ค.

๐ ์ ๊ท ํํ์(Regualr Expression)
๐ฝ ์ ๊ท ํํ์ ์ ๋ฆฌํ
| ํ ํ ์ | ์ค ๋ช |
| ^ | ๋ฌธ์์ด์ ์์์ ์๋ฏธ |
| $ | ๋ฌธ์์ด์ ์ข ๋ฃ๋ฅผ ์๋ฏธ |
| . | ์์์ ํ ๋ฌธ์ (๋ฌธ์์ ์ข ๋ฅ ์๊ด ์์ผ๋, \ ๋ ๋ฃ์ ์ ์๋ค.) |
| * | ์ ๋ฌธ์๊ฐ ์์ ์๋ ์๊ณ , ๋ฌดํ์ ์ผ๋ก ๋ง์ ์๋ ์์์ ์๋ฏธ |
| + | ์ ๋ฌธ์๊ฐ ํ๋ ์ด์์ ์๋ฏธ |
| ? | ์ ๋ฌธ์๊ฐ ์๊ฑฐ๋, ํ๋ ์์์ ์๋ฏธ |
| [] | ๋ฌธ์์ ์งํฉ์ด๋, ๋ฒ์๋ฅผ ์๋ฏธํ๋ฉฐ, ๋ ๋ฌธ์ ์ฌ์ด๋ - ๊ธฐํธ๋ฅผ ํตํด ๋ฒ์๋ฅผ ํํ. [] ์์์ ^๊ฐ ๋จผ์ ์กด์ฌํ๋ฉด `not`์ ์๋ฏธ [a-zA-Z] a~z, A~z ์ค ํ๋์ ๋ฌธ์ ์๋ฏธ []๋ ํ๊ฐ์ ๋ฌธ์๋ฅผ ์๋ฏธํ๊ธฐ๋ ํจ. [abc] a,b,c ์ค ํ๋์ ๋ฌธ์ ์๋ฏธ [^abc] a,b,c ์ธ์ ํ๋์ ๋ฌธ์ ์๋ฏธ |
| {} | ํ์ ๋๋ ๋ฒ์๋ฅผ ์๋ฏธ |
| {n} | ์ ํํ n๊ฐ |
| {n,} | ์ต์ํ n๊ฐ |
| {n,m} | n๊ฐ ๋ถํฐ m๊ฐ๊น์ง |
| () | ์๊ดํธ ์์ ๋ฌธ์๋ฅผ ํ๋์ ๋ฌธ์๋ก ์ธ์ํ๊ฒ ๋ค๋ ์๋ฏธ |
| | | Pattern ์์์ or ์ฐ์ฐ ์ํ์ ํ๊ณ ์ ํ ๋ ์ฌ์ฉ |
| \s | ๊ณต๋ฐฑ ๋ฌธ์ ์๋ฏธ |
| \S | ๊ณต๋ฐฑ ๋ฌธ์๊ฐ ์๋ ๋๋จธ์ง ๋ฌธ์ ์๋ฏธ |
| \w | Alphabet ๋๋ ์ซ์ ๋๋ `์ธ๋๋ฐ(_)`๋ฅผ ์๋ฏธ |
| \W | Alphabet ๋๋ ์ซ์ ๋๋ `์ธ๋๋ฐ(_)`๋ฅผ ์ ์ธํ ๋ฌธ์๋ฅผ ์๋ฏธ |
| \d | ์ ์ [0-9]์ ๋๊ฐ์ ์๋ฏธ |
| \D | ์ซ์๋ฅผ ์ ์ธํ ๋ชจ๋ ๋ฌธ์ |
| \ | ์ ๊ทํํ์ ์ญ์ฌ๋์( \ )๋ ํ์ฅ ๋ฌธ์๋ฅผ ์๋ฏธ. ์ญ์ฌ๋์ ๋ค์์ ์ผ๋ฐ ๋ฌธ์๊ฐ ์ค๋ฉด ํน์๋ฌธ์๋ก ์ทจ๊ธํ๊ณ , ์ญ์ฌ๋์ ๋ค์์ ํน์๋ฌธ์๊ฐ ์ค๋ฉด ๊ทธ ๋ฌธ์ ์์ฒด๋ฅผ ์๋ฏธ(์ผ๋ฐ ๋ฌธ์๋ก ์ทจ๊ธ) |
| (?i) | ์ ๋ถ๋ถ (?i)๋ผ๋ Option์ ๋ฃ์ด์ฃผ๋ฉด ๋, ์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์๊ฒ ๋ค๋ ์๋ฏธ |
๐ฝ ์์ฃผ ์ฐ์ด๋ ์ ๊ท์ Pattern
| ๋ถ ๋ฅ | ์ ๊ท ์ Pattern |
| ์ซ์ | ^[0-9]+$ |
| ์(์, ๋)๋ฌธ์ | ^[a-zA-Z]+$ |
| ํ๊ธ | ^[๊ฐ-ํฃ]+$ |
| ์์ด, ์ซ์ ์กฐํฉ | ^[a-zA-Z0-9]+$ |
| ๋น๋ฐ๋ฒํธ (์ซ์, ์(์, ๋)๋ฌธ์ ํฌํจ 6 ~ 12์๋ฆฌ ์ด๋ด) |
^[a-zA-Z0-9]{6,12}$ |
| ๋น๋ฐ๋ฒํธ (์ซ์, ์(์, ๋)๋ฌธ์, ํน์๋ฌธ์ ํฌํจ 8~15์๋ฆฌ ์ด๋ด) |
^.*(?=^.{8,15}$)(?=.*\d)(?=.*[a-zA-Z])(?=.*[!@#$%^&+=].*$ |
| ^[0-9a-zA-Z]+@[0-9a-zA-Z]+\\.([a-z]+)*$ | |
| ํด๋์ ํ ๋ฒํธ | ^01(?:0|1|[6-9])?(\\d{3}|\\d{4})?(\\d{4})$ |
| ์ผ๋ฐ์ ํ ๋ฒํธ | ^0(?:2-9)?(?:2-9)?(\\d{3}|\\d{4})?(\\d{4})$ |
| ์ฃผ๋ฏผ๋ฑ๋ก ๋ฒํธ | ^\d{6}\-[1-4]\d{6}$ |
| File ํ์ฅ์ | ^\\S+(?i)(txt|pdf|hwp|xls|png|jpg)& |
| ์ด ์ค File ํ์ฅ์ | ^(.+?)(\\.tar)?\\.gz)$ |
๐ฆ ํ๊ธ ํฌํจ ์ฌ๋ถ ํ์ธ

โ `matches()`๋ `String`์ ์ฌ์ฉํ ์ ์๋ Method.
โ `*`์ ๋งจ ์์ ์ฌ ์ ์๊ธฐ ๋๋ฌธ์ ์์ `.`์ ์ ์ธ.
โ `[ใฑ-ใ
]` ์ ใฑ ๋ถํฐ ใ
๊น์ง ์๋ฏธ.
โ '[ใ
-ใ
ฃ]`๋ ใ
๋ถํฐ ใ
ฃ ๊น์ง ์๋ฏธ.
โ '[๊ฐ-ํฃ]`์ ํ๊ธ ์, ๋ชจ์์ ์กฐํฉํ์ฌ ๋ง๋ค ์ ์๋ ๋ชจ๋ ํ๊ธ ์๋ฏธ.
โ `+`๋ ํ๊ธ์ด ํ๋ ์ด์ ๋ฐ๋ณต๋จ์ ์๋ฏธ.
โ `.*`์ ํ ๊ธ์ ๋๋ ๋ฌธ์์ด ์๋ฏธ.
๐ฆ ํธ๋ํฐ ๋ฒํธ Pattern ๋ง๋ค๊ธฐ
๋ํ๋ฏผ๊ตญ์์ ์ฌ์ฉํ๋ ํธ๋ํฐ ๋ฒํธ Pattern์ ํ๋ฒ ๋ง๋ค์ด ๋ณผ ๊ฒ์ด์์.
์ฐ๋ฆฌ๋๋ผ์ ํธ๋ํฐ ๋ฒํธ๋ 3๊ฐ๋ก ๊ตฌ๋ถ๋์ด ์ฌ์ฉํ๊ณ ์๋ ๊ฒ์ด์์.
์ฒซ๋ฒ์งธ ์๋ฆฌ์๋ ์๋์ ๊ฐ์ ๋ฒํธ๋ค์ด ์ฌ ์ ์๋ต๋๋ค.
010
011
016
017
018
019
์ง๊ธ์ `010`๋ง ์ด์ฉ๋๊ณ ์์ง๋ง, ์ ๋ฌด๋ก ์ธํด ํธ๋ํฐ ๋ฒํธ๋ฅผ ๋ฐ๊พธ์ง ๋ชปํ์ จ๋ ๋ถ๋ค์ ์ด์ฉ๋ฉด ์์ง๋ ์๋ `Pattern`์ ์ด์ฉํ๊ณ ๊ณ์ค์ง ๋ชจ๋ฅด๋ ๊ฒ์ด์์.
๋๋ฒ์งธ ์๋ฆฌ๋ 3 ~ 4์๋ฆฌ์ ์์์ ์ซ์๊ฐ ์ค๋ฉด ๋๋ ๊ฒ์ด์์.
์ธ๋ฒ์งธ ์๋ฆฌ๋ ์ผ๋ฐ์ ์ผ๋ก 4์๋ฆฌ๋ฅผ ์ง์ ํ๊ณ ์์ผ๋ ๊ทธ๊ฒ์ ๋ฐ๋ฅด๋๋ก ํ ๊ฒ์ด์์.
์๋ฆฟ์ ์ฌ์ด์ ์๋ฌด ํ๊ธฐ๋ ์ฌ์ฉํ์ง ์๊ฑฐ๋ `-`ํน์ `.`์ผ๋ก ๊ตฌ๋ถํ๋ ๊ฒ์ ํ์ฉํ๋ ๊ฑธ๋ก ์์ฑํด ๋ณผ ๊ฒ์ด์์.
์๋ฅผ ๋ค์๋ฉด
01012345678
010-1234-5678
010.1234.5678
์ด๋ ๊ฒ ๋ง์ด์์.
โบ ์ฒซ๋ฒ์งธ ์๋ฆฌ์ ์ธ ์๋ฆฌ
`^01`
์ ๊ท ํํ์ `Pattern`์ ์๋ฏธํ๋ `^`๋ฅผ ์์์ผ๋ก `01`์ ์ถ๊ฐํ ๊ฒ์ด์์.
๋ฌธ์์ด์ ์์์ `01`๋ก ์์ํ ๊ฑฐ์ผ! ๋ผ๊ณ ์๋ ค์ค ๊ฒ์ด์์.
`01(?:0|1|[6-9])`
`01` ๋ค์์ ์ค๋ ๊ฐ์ผ๋ก 0, 1 ๋๋ 6 ~ 9 ์ฌ์ด ๊ฐ์ด ํ์ฉ๋๋๋ก ํ ๊ฒ์ด์์.
โบ ๋๋ฒ์งธ ์๋ฆฌ
`01(?:0|1|[6-9])(\\d{3}|\\d{4})`
3์๋ฆฌ ๋๋ 4์๋ฆฌ์ ์์์ ์ซ์๋ฅผ ํ์ฉ๋๋๋ก ํ ๊ฒ์ด์์.
โบ ์ธ๋ฒ์งธ ์๋ฆฌ
`01(?:0|1|[6-9])(\\d{3}|\\d{4})(\\d{4})$`
๋ง์ง๋ง 4์๋ฆฌ์ ์ซ์๋ฅผ ์ง์ ํ ๊ฒ์ด์์. ๊ทธ๋ฆฌ๊ณ , ํํ์์ ์ข ๋ฃ๋ฅผ ์๋ฆฌ๋ `$`๋ก ๋ง๋ฌด๋ฆฌ ํด์ค ๊ฒ์ด์์.
โบ ๊ตฌ๋ถ๊ฐ ์ถ๊ฐ
ํธ๋ํฐ ๋ฒํธ๋ฅผ ์
๋ ฅ์ `-`, `.`์ ์ถ๊ฐํด์ ์
๋ ฅํ๋ ๊ฒฝ์ฐ๊ฐ ์ข
์ข
์๋ ๊ฒ์ด์์.
์๋ฌด๋ฐ ํ๊ธฐ๋ฅผ ํ์ง ์๊ณ , ์ซ์๋ง ์
๋ ฅ ๋ฐ๊ฑฐ๋, ์์ ํน์๋ฌธ์๋ฅผ ํ์ฉํ๋๋ก ํด ๋ณผ ๊ฒ์ด์์.
`01(?:0|1|[6-9])[.-]?(\\d{3}|\\d{4})[.-]?(\\d{4})$`
`[.-]?`
์ด ๋ป์ `.`, `-` ๊ฐ์ด ์๊ฑฐ๋, ๋จ ํ๊ฐ๋ง ์กด์ฌํ๋ ๊ฒ์ ์๋ฏธํ๋ ๊ฒ์ด์์.
๐ฝ Pattern Class
โ ์ ๊ท ํํ์์ ๋ํ ๋ฌธ์์ด ๊ฒ์ฆ.
โ ๊ณต๊ฐ๋ ์์ฑ์ ๋ฏธ ์ ๊ณต.
โ `Pattern` ์์ฑ ์ `Pattern` ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ์ ์ `compile` Method ํธ์ถ.
โ 'matches()`๋ฅผ ํ์ฉํ์ฌ ๊ฒ์ฆ
โ regex
- ์ ๊ท ํํ์
โ input
- ๊ฒ์ฆํ ๋ฌธ์์ด
์์ ์ฝ๋

๐ฝ Matcher Class
โ `Pattern`์ ํด์ํ๊ณ , ์
๋ ฅ ๋ฌธ์์ด์ ๋ํด ์ผ์น ์์
์ ์ํํ๋ ์์ง.
โ `Pattern` Class์ ๋์ผํ๊ฒ ๊ณต๊ฐ๋ ์์ฑ์ ๋ฏธ ์ ์.
โ `Pattern` ๊ฐ์ฒด์ `matcher()`๋ฅผ ํธ์ถํด์ ๊ฒฐ๊ณผ๊ฐ์ ์ป๋๋ค.
โ 'matches()`ํ์ฉํ์ฌ ๊ฒ์ฆ
โ regex
- ์ ๊ท ํํ์
โ input
- ๊ฒ์ฆํ ๋ฌธ์์ด
์์ ์ฝ๋


'Back-End ์์ ์ค > Spring Framework' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [Spring] Spring Security - Method Security (0) | 2022.03.30 |
|---|---|
| [Spring] Spring Security ์ธ์ฆ ์ ์ฐจ Interface | UserDetails์ UserDetailsService (0) | 2022.03.29 |
| [Spring] ResponseEntity (0) | 2022.03.28 |
| [Spring] @PathVariable ๊ทธ๋ฆฌ๊ณ @RequestParam (0) | 2022.03.22 |
| [Spring] @Controller์ @RestController์ ์ฐจ์ด (0) | 2022.03.22 |