[Spring] @Validλ₯Ό μ΄μ©ν @RequestBody κ²μ¦ / Exception Handling / μ κ· ννμ
π @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
- κ²μ¦ν λ¬Έμμ΄
μμ μ½λ