前の記事は以下です。
yagibrary.hatenablog.com
yagibrary.hatenablog.com
yagibrary.hatenablog.com
フィールドにpasswordの追加
package com.zosh.model; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import java.time.LocalDateTime; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String fullName; private String email; private String phone; private String role; private LocalDateTime createdAt; private LocalDateTime updatedAt; private String password; public User() { } public User(String fullName, String email, String phone, String role, LocalDateTime createdAt, LocalDateTime updatedAt) { this.fullName = fullName; this.email = email; this.phone = phone; this.role = role; this.createdAt = createdAt; this.updatedAt = updatedAt; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } public LocalDateTime getUpdatedAt() { return updatedAt; } public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } }
validationの依存関係の追加
validationの依存関係を追加します。pom.xmlを開いた状態でAlt + Insertを押下します。
pom.xmlは以下のようになります。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.4.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.zosh</groupId> <artifactId>user-service</artifactId> <version>0.0.1-SNAPSHOT</version> <name>user-service</name> <description>user service for salon booking system</description> <url/> <licenses> <license/> </licenses> <developers> <developer/> </developers> <scm> <connection/> <developerConnection/> <tag/> <url/> </scm> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>jakarta.persistence</groupId> <artifactId>jakarta.persistence-api</artifactId> <version>3.1.0</version> <!-- バージョンは適宜調整 --> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
プロジェクトをリロードしておきます。
emailとパスワードを必須項目にする
emailフィールドとpasswordフィールドに@NotBlankを付与します。
package com.zosh.model; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.validation.constraints.NotBlank; import java.time.LocalDateTime; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String fullName; @NotBlank(message = "email is mandatory") private String email; private String phone; private String role; private LocalDateTime createdAt; private LocalDateTime updatedAt; @NotBlank(message = "password id mandatory") private String password; public User() { } public User(String fullName, String email, String phone, String role, LocalDateTime createdAt, LocalDateTime updatedAt) { this.fullName = fullName; this.email = email; this.phone = phone; this.role = role; this.createdAt = createdAt; this.updatedAt = updatedAt; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } public LocalDateTime getUpdatedAt() { return updatedAt; } public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } }
UserController.javaに移動し、createUserメソッドの引数に@Validを付与します。
package com.zosh.controller; import com.zosh.model.User; import com.zosh.repository.UserRepository; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Optional; @RestController public class UserController { @Autowired private UserRepository userRepository; @PostMapping("/api/users") public User createUser(@RequestBody @Valid User user) { return userRepository.save(user); } @GetMapping("/api/users") public List<User> getUsers() { return userRepository.findAll(); } @GetMapping("/api/users/{userId}") public User getUserById(@PathVariable("userId") Long id) throws Exception { Optional<User> opt = userRepository.findById(id); if(opt.isPresent()) { return opt.get(); } throw new Exception("user not found"); } @PutMapping("/api/users/{id}") public User updateUser(@RequestBody User user, @PathVariable Long id) throws Exception { Optional<User> opt = userRepository.findById(id); if(opt.isEmpty()) { throw new Exception("user not found with id"+id); } User existingUser = opt.get(); existingUser.setFullName(user.getFullName()); existingUser.setEmail(user.getEmail()); existingUser.setRole(user.getRole()); return userRepository.save(existingUser); } @DeleteMapping("/api/users/{id}") public String deleteByUserId(@PathVariable Long id) throws Exception { Optional<User> opt = userRepository.findById(id); if(opt.isEmpty()) { throw new Exception("user not exist with id"+id); } userRepository.deleteById(opt.get().getId()); return "User deleted"; } }
Postmanにいき、メールとパスワードなしでユーザ登録を試みます。
すると下記のようなエラーになります。
{ "timestamp": "2025-01-27T12:35:40.455+00:00", "status": 400, "error": "Bad Request", "trace": "org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public com.zosh.model.User com.zosh.controller.UserController.createUser(com.zosh.model.User) with 2 errors: [Field error in object 'user' on field 'password': rejected value [null]; codes [NotBlank.user.password,NotBlank.password,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.password,password]; arguments []; default message [password]]; default message [password id mandatory]] [Field error in object 'user' on field 'email': rejected value [null]; codes [NotBlank.user.email,NotBlank.email,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.email,email]; arguments []; default message [email]]; default message [email is mandatory]] \r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:159)\r\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:226)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:180)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:986)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:891)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)\r\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)\r\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)\r\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)\r\n\tat java.base/java.lang.Thread.run(Thread.java:1589)\r\n", "message": "Validation failed for object='user'. Error count: 2", "errors": [ { "objectName": "user", "field": "password", "rejectedValue": null, "codes": [ "NotBlank.user.password", "NotBlank.password", "NotBlank.java.lang.String", "NotBlank" ], "arguments": [ { "codes": [ "user.password", "password" ], "arguments": null, "defaultMessage": "password", "code": "password" } ], "defaultMessage": "password id mandatory", "bindingFailure": false, "code": "NotBlank" }, { "objectName": "user", "field": "email", "rejectedValue": null, "codes": [ "NotBlank.user.email", "NotBlank.email", "NotBlank.java.lang.String", "NotBlank" ], "arguments": [ { "codes": [ "user.email", "email" ], "arguments": null, "defaultMessage": "email", "code": "email" } ], "defaultMessage": "email is mandatory", "bindingFailure": false, "code": "NotBlank" } ], "path": "/api/users" }
メールとパスワードをつけて登録するとうまくいきます。
ただ一つ問題がありまして、現状メールがただの文字列でも登録できてしまうのでそこを修正します。
emailフィールドに@Emailを付与します。
package com.zosh.model; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import java.time.LocalDateTime; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String fullName; @NotBlank(message = "email is mandatory") @Email(message = "Email should be valid") private String email; private String phone; private String role; private LocalDateTime createdAt; private LocalDateTime updatedAt; @NotBlank(message = "password id mandatory") private String password; public User() { } public User(String fullName, String email, String phone, String role, LocalDateTime createdAt, LocalDateTime updatedAt) { this.fullName = fullName; this.email = email; this.phone = phone; this.role = role; this.createdAt = createdAt; this.updatedAt = updatedAt; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } public LocalDateTime getUpdatedAt() { return updatedAt; } public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } }
もう一度ユーザ登録を試みますとエラーになります。
メールを正しい形式にすると登録できます。
ロールも必須項目にします。
package com.zosh.model; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import java.time.LocalDateTime; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String fullName; @NotBlank(message = "email is mandatory") @Email(message = "Email should be valid") private String email; private String phone; @NotBlank(message = "role is mandatory") private String role; private LocalDateTime createdAt; private LocalDateTime updatedAt; @NotBlank(message = "password id mandatory") private String password; public User() { } public User(String fullName, String email, String phone, String role, LocalDateTime createdAt, LocalDateTime updatedAt) { this.fullName = fullName; this.email = email; this.phone = phone; this.role = role; this.createdAt = createdAt; this.updatedAt = updatedAt; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } public LocalDateTime getUpdatedAt() { return updatedAt; } public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } }
フィールドにusernameを追加したり、他のフィールドにアノテーションをつけたりします。
最終的にこのようなコードになります。
package com.zosh.model; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; import java.time.LocalDateTime; @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String fullName; @NotBlank(message = "username is mandatory") private String username; @NotBlank(message = "email is mandatory") @Email(message = "Email should be valid") private String email; private String phone; @NotBlank(message = "role is mandatory") private String role; @CreationTimestamp private LocalDateTime createdAt; @UpdateTimestamp private LocalDateTime updatedAt; @NotBlank(message = "password id mandatory") private String password; public User() { } public User(String fullName, String email, String phone, String role, LocalDateTime createdAt, LocalDateTime updatedAt) { this.fullName = fullName; this.email = email; this.phone = phone; this.role = role; this.createdAt = createdAt; this.updatedAt = updatedAt; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public LocalDateTime getCreatedAt() { return createdAt; } public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } public LocalDateTime getUpdatedAt() { return updatedAt; } public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } }