如何在spring mvc应用程序中向数据库添加重复的用户名时处理异常

时间:2016-08-04 15:48:28

标签: java mysql spring spring-mvc

我正在构建spring mvc应用程序。我想不赞成添加重复(用户名是主键)条目,并在视图中通知选择另一个用户名。

我正在处理注册用户选项。一切正常,直到我把用户名已经存在。好吧,这是故意的,因为用户名列是我数据库中的主键。

我正在寻找一个处理这个的选项:

这是我的SQL表

 create table users(
  username varchar(50) not null primary key,
  password varchar(50) not null);

这是我的存储库:

@Repository

class UserRepositoryImpl implements UserRepository{

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Override
    public void addUser(User user) throws MySQLIntegrityConstraintViolationException {
        /*language=SQL*/
        String SQL_ADD_USER= "INSERT INTO users VALUES (?,?)";

        String username  = user.getUsername();
        String password  = user.getPassword();
        jdbcTemplate.update(SQL_ADD_USER, username, password);

    }
}

这是我的Controller类的一部分:

@RequestMapping(value="/register", method = RequestMethod.GET)
public String registerPage(@ModelAttribute("user") User user){return "register";}

@RequestMapping(value="/register", method=RequestMethod.POST)
public String processRegisterUser(@ModelAttribute("user") User user, BindingResult result){

    try {
        userRepository.addUser(user);
    } catch (com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException e) {

        //some line of code that would add information to the view that user with given username already exists.
    }


    return "redirect:/login";
}

如您所见,我尝试处理在添加重复条目期间发生的异常。这就是我将此子句throws MySQLIntegrityConstraintViolationException放在public void addUser(User user)中的原因。在下一步中,我想在public String processRegisterUser方法中处理此异常,以便我可以在视图中通知用户已占用给定用户名。好吧,它不起作用。我无法处理com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException并且在添加重复错误而不是警告时我得到:

 HTTP Status 500 - Request processing failed; nested exception is org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [INSERT INTO users VALUES (?,?)]; Duplicate entry 'user' for key 'PRIMARY'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'user' for key 'PRIMARY'

type Exception report

message Request processing failed; nested exception is org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [INSERT INTO users VALUES (?,?)]; Duplicate entry 'user' for key 'PRIMARY'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'user' for key 'PRIMARY'

description The server encountered an internal error that prevented it from fulfilling this request.

exception

    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [INSERT INTO users VALUES (?,?)]; Duplicate entry 'user' for key 'PRIMARY'; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'user' for key 'PRIMARY'
        org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
        org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
        org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
        org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
        org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
        org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)
        org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
        org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)

如果您需要任何详细信息,请发表评论。

4 个答案:

答案 0 :(得分:1)

您只处理MySQLIntegrityConstraintViolationException,而不是其他异常:NestedServletException和DuplicateKeyException,因此您将获得stacktrace并且您的try / catch无法正常工作。

BTW,为什么不简单地创建一个额外的方法来检查用户名是否已经存在,如果是,则显示错误消息,否则添加用户。

class UserRepositoryImpl implements UserRepository{
    //.....
    public int isUsernameExist(String username){
        String sql = "SELECT COUNT(*) FROM users WHERE username=?";
        return jdbcTemplate.queryForObject(sql, new Object[] { username }, String.class);
    }
    //....
}

@RequestMapping(value="/register", method=RequestMethod.POST)
public String processRegisterUser(@ModelAttribute("user") User user, BindingResult result){
    int status = userRepository.isUserExist(user.getUsername());
    if(status==1){
        //Username exist... redirect and display error msg.
    } else {
        userRepository.addUser(user);
    }
    //.....
}

答案 1 :(得分:1)

您正在使用spring jdbcTemplate进行数据库连接,并且它有自己的异常层次结构,因此您可以尝试捕获spring异常org.springframework.dao.DuplicateKeyException

答案 2 :(得分:1)

尝试articleelse

中所述的Query.uniqueResult()
public Account getAccountByAccountIdAndType(Long accountId, AccountType accountType) {

    Account account = null;
    try {
        Query query = getSession().getNamedQuery("getAccountByAccountId");
        query.setLong("accountId", accountId); 
        query.setString("accountType", AccountType.SAVING.toString());
        Account account = (Account)Query.uniqueResult();
    } catch(NonUniqueResultException) {
        throw new RuntimeException("Two account found with same account number and type : Acc No-" + accountId);
    }
    if (account == null) {
         throw new RuntimeException("Unable to find Account for account number :" + accountId);
    }
    return account;
}

实体类

@NamedQuery(
name = "getAccountByAccountId",
query = "from Account where username = :username")
@Entity
@Table(name = "account")
public class Account {

答案 3 :(得分:0)

我将通过捕获异常来解决该问题(以避免竞争条件),然后将一个错误添加到BindingResult中,以便能够在(JSP / Thymeleaf)视图模板中显示该错误。


@Controller
public class UserController {

  private final UserService userService;

  public UserController(UserService userService) {

    this.userService = userService;
  }

  /**
   * Adds new a user and redirect to users if there are no errors otherwise return add user template.
   */
  @PostMapping("/admin/add_user")
  public String postUser(Model model, @Valid UserForm userForm, BindingResult result) {

    if (result.hasErrors()) {
      // Maybe add attributes to the model here. Do not redirect when there are errors.

      return "add_user";
    }

    try {
      userService.createUser(
          User.withUsername(userForm.getUsername()).password(userForm.getPassword()).roles("ADMIN").build());
    } catch (final DuplicateKeyException e) {
      result.rejectValue("username", "usernameInUse", "Username is already in use");

      return postUser(model, userForm, result);
    }

    // Redirect after post if there are no errors
    return "redirect:/admin/users";
  }

}

用户表单包含标准的jsr 303验证批注。

@Data
public class UserForm {

  @Length(min = 1, max = 50)
  @NotEmpty
  private String username;

  @NotEmpty
  private String password;
}