Java Web 项目学习(二) 开发注册功能

 访问注册界面:

  三层(Controller、Service、DAO) 只需要 Controller 就可以完成。

  • 在Controller下
    • 构建,LoginController。
    • 找到对应HTML界面,引入模板thymeleaf。做响应修改
      • 相对路径修改为模板样式 @{}
            <link rel="stylesheet" th:href="@{/css/global.css}" />
            <link rel="stylesheet" th:href="@{/css/login.css}" />
            <script th:src="@{/js/global.js}"></script>
            <script th:src="@{/js/register.js}"></script>
        View Code
      • 找到对应首页的HTML界面index.html,做对应修改,让其可以跳转到注册界面,同样是@{}替换

                        <!-- 功能 -->
                        <div class="collapse navbar-collapse" id="navbarSupportedContent">
                            <ul class="navbar-nav mr-auto">
                                <li class="nav-item ml-3 btn-group-vertical">
                                    <a class="nav-link" th:href="@{/index}">首页</a>
                                </li>
                                <li class="nav-item ml-3 btn-group-vertical">
                                    <a class="nav-link position-relative" href="site/letter.html">消息<span class="badge badge-danger">12</span></a>
                                </li>
                                <li class="nav-item ml-3 btn-group-vertical">
                                    <a class="nav-link" th:href="@{/register}">注册</a>
                                </li>
        View Code

        因为头部(导航栏)在每个页面复用,每个都修改,十分繁琐。因此复用一下。在index中起别名。将register中的header替换掉。
        index.html  <header class="bg-dark sticky-top" th:fragment="header"> th:fragment="" 起别名
        register.html <header class="bg-dark sticky-top" th:replace="index::header"> th:replace="index::header"     (两个冒号)

 提交注册数据:

    • 准备工作

      • 导入包   Commons Lang  用来判断为空、不合法的情况。(https://mvnrepository.com/)

      • 发邮件需要带激活连接,激活连接在我们网站内。所以在application.properties中定义链接。
      • 写一个工具类,提供方法以供我们使用。
        /**
         * 提供静态的方法,不用容器托管,直接调。
         *
         */
        public class CommunityUtil {
            //生成随机字符串
            public static String generateUUID(){
                return UUID.randomUUID().toString().replaceAll("-"."");
            }
        
            //MD5 加密
            //用户密码 + salt  再做加密
            public static String md5(String key){
                if(StringUtils.isEmptyOrWhitespaceOnly(key)){
                    return null ;
                }
                return DigestUtils.md5DigestAsHex(key.getBytes());
            }
        }
        View Code
    • UserService
      发邮件,针对用户,因此使用。注入相关信息。固定值的注入用 @Value(“”)
      @Service
      public class UserService implements CommunityConstant {
          @Autowired
          private UserMapper userMapper;
          @Autowired
          private MailClient mailClient;  //发邮件
          @Autowired
          private TemplateEngine templateEngine;   //模板引擎
      
      
          //发邮件,连接, 配置域名和项目名
          @Value("${server.servlet.context-path}")
          private String contextPath;
          @Value("${community.path.domain}")
          private String domain;
      
      
      
      
          //根据用户id查询用户名
          public User findUserById(int id){
              return userMapper.selectById(id);
          }
      
      
          public Map<String,Object> register(User user){
              Map<String,Object> map= new HashMap<>();
      
              //空值处理
              if (user == null){
                  throw new IllegalArgumentException("参数不能为空");
              }
              //以下是业务层面的错误,告诉他不对
              if(StringUtils.isEmptyOrWhitespaceOnly(user.getUsername())){
                  map.put("usernameMsg","账号不能为空");
                  return map;
              }
              if(StringUtils.isEmptyOrWhitespaceOnly(user.getPassword())){
                  map.put("passwordMsg","密码不能为空");
                  return map;
              }
              if(StringUtils.isEmptyOrWhitespaceOnly(user.getEmail())){
                  map.put("emailMsg","邮箱不能为空");
                  return map;
              }
              //验证账号
              User uExist =userMapper.selectByName(user.getUsername());
              if (uExist != null) {
                  map.put("usernameMsg","该账号已经存在");
                  return map;
              }
      
              //验证邮箱
              uExist = userMapper.selectByEmail(user.getEmail());
              if (uExist != null) {
                  map.put("emailMsg","该邮箱已经被注册");
                  return map;
              }
      
              //注册用户
              user.setSalt(CommunityUtil.generateUUID().substring(0,5));
              user.setPassword(CommunityUtil.md5(user.getPassword()+ user.getSalt()));
              user.setStatus(0);
              user.setType(0);
              user.setActivationCode(CommunityUtil.generateUUID());
              //创建随机头像
              user.setHeaderUrl(String.format("http://images.nowcoder.com/head/%dt.png",new Random().nextInt(1000)));
              user.setCreateTime(new Date());
              userMapper.insertUser(user);
      
      
              //给用户发送邮件,考虑模板是谁?进行部分修改
              Context context = new Context();
              context.setVariable("email",user.getEmail());
              //http://localhost:8080/comminity/activation/userid/code
              String url = domain + contextPath +"/activation/"+ user.getId() +"/" +user.getActivationCode();
              context.setVariable("url",url);
              String content = templateEngine.process("/mail/activation",context);
              mailClient.sendMail(user.getEmail(),"激活账号",content);
      
              return map;
          }
      
      
      
          //成功激活。重复激活没有意义,激活码是伪造的,
          public int activation(int userId , String code){
              //查到用户,判断状态是否已激活,匹配激活码
              User user = userMapper.selectById(userId);
              if(user.getStatus() ==1){
                  return ACTIVATION_REPEATION;
              }
              else if(user.getActivationCode().equals(code)){
                  userMapper.updateStatus(userId,1);
                  return ACTIVATION_SUCCESS;
              }else {
                  return  ACTIVATION_FAILURE;
              }
      
          }
      }
      View Code

    • LoginController
      • 注入UserService,按照逻辑写对应代码。
            @RequestMapping(path = "/register",method = RequestMethod.POST)
            public  String  register(Model model, User user){ //返回视图的名字
        
                Map<String, Object> map = userService.register(user);
                if (map == null || map.isEmpty()){//注册成功,跳转首页
                    model.addAttribute("msg","注册成功,已向您发送一封激活邮件,请尽快激活!");
                    model.addAttribute("target","/index");
                    return "/site/operate-result";
                }else{
                    model.addAttribute("usernameMsg",map.get("usernameMsg"));
                    model.addAttribute("emailMsg",map.get("emailMsg"));
                    model.addAttribute("passwordMsg",map.get("passwordMsg"));
                    return "/site/register";
                }
            }
      • 修改对应HTML(index)
        • 常规操作,xmlns=“”...”   替换相对路径。 修改替换头部使用index的header。
        • 对表单进行操作 <form class="mt-5" method="post" th:action="@{/register}"> 同时注意需要有提交按钮 <button type="submit">
        • 在input添加name属性,name=“XX” 。其中XX应与Controller中User中的属性对应。密码邮箱情况同理。确认密码不用,是前台的工作 。
          <input type="text" class="form-control" id="username" name="username" placeholder="请输入您的账号!" required>
        • (成功跳转 首页,通过 site/operate-result)
          <!-- 内容 -->
                  <div class="main">
                      <div class="container mt-5">
                          <div class="jumbotron">
                              <p class="lead" th:text="${msg}">您的账号已经激活成功,可以正常使用了!</p>
                              <hr class="my-4">
                              <p>
                                  系统会在 <span id="seconds" class="text-danger">8</span> 秒后自动跳转,
                                  您也可以点此 <a id="target" th:href="@{${target}}" class="text-primary">链接</a>, 手动跳转!
                              </p>
                          </div>
                      </div>
                  </div>
          View Code
        • (失败返回注册界面,提示信息 ,site/index)  这段确认密码对应部分也需要修改

          <input type="text" class="form-control"
                 th:value="${user!= null? user.username:''}"
                 id="username" name="username" placeholder="请输入您的账号!" required>

          这段确认密码不需要修改

          <div class="invalid-feedback" th:text="${usernameMsg}">该账号已存在!</div>

          div的框是否显示通过input中的is-invalid 控制,因此我们需要动态的判断,因此修改最终的对应input为

          <input type="text"
                  th:class="|form-control ${usernameMsg!=null? 'is-invalid':''}|"
                  th:value="${user!= null? user.username:''}"
                  id="username" name="username" placeholder="请输入您的账号!" required>
          <div class="invalid-feedback" th:text="${usernameMsg}"> 该账号已存在! </div>
      • 遇到的各种错误
        • There was an unexpected error (type=Internal Server Error, status=500). Error resolving template [/register], template might not exist or might not be accessible by any of the configured Template Resolvers
          在controller中的返回值    return "/register";  而应该是 return "/site/register";  导致找不到返回界面了。
          想不明白为什么在  @RequestMapping(path = "/register",method = RequestMethod.POST)  就不需要加路径。可能是spring自动对应了。

        • 提示已发送邮件,但是登陆邮箱没收到
          ——换个邮箱试试!我一开始用的是QQ邮箱。可能发的太多了。后面收不到,垃圾箱里也没有。后来重新申请的网易邮箱就好了。

           

激活注册账号:

  • 激活执行后有三种状态。1 激活成功,2 重复激活(无意义),3 激活码伪造。 定义工具类下的CommunityConstant 用来表示状态。接口就可以。常量一般采用大写。ctrl+shif+u大写转换。
    public interface CommunityConstant {
        /**
         * 激活成功
         */
        int ACTIVATION_SUCCESS =0;
    
        /**
         * 重复激活
         */
        int ACTIVATION_REPEATION =1;
    
        /**
         * 激活失败
         */
        int ACTIVATION_FAILURE =2;
    }
    View Code
  • 在UserService中加一个方法。改变用户状态。
    //成功激活。重复激活没有意义,激活码是伪造的,
        public int activation(int userId , String code){
            //查到用户,判断状态是否已激活,匹配激活码
            User user = userMapper.selectById(userId);
            if(user.getStatus() ==1){
                return ACTIVATION_REPEATION;
            }
            else if(user.getActivationCode().equals(code)){
                userMapper.updateStatus(userId,1);
                return ACTIVATION_SUCCESS;
            }else {
                return  ACTIVATION_FAILURE;
            }
    
        }
    View Code
  • 在Controller当中,处理请求。请求的页面是发送的那个邮件,邮件就是一个html。
    • 声明路径按照Service所给出的。从路径中取值传入代码中使用@PathVariable("userId") int userid,
    • 无论成功还是失败,都给用户提示(跳转到提示页面,页面根据不同情况做不同反映),成功跳到登录界面,失败跳到首页。
      // http://localhost:8080/comminity/activation/userid/code
          @RequestMapping(path="activation/{uderId}/{code}",method = RequestMethod.GET)
          public String avtivation(Model model, @PathVariable("userId") int userid, @PathVariable("code") String code ){
              int result =userService.activation(userid,code);
              //无论成功还是失败,都给用户提示(跳转到提示页面,页面根据不同情况做不同反映),成功跳到登录界面,失败跳到首页
              if(result ==ACTIVATION_SUCCESS){
                  model.addAttribute("msg","激活成功,您的账号已可以正常使用!");
                  model.addAttribute("target","/login");
      
              }else if (result ==ACTIVATION_REPEATION){
                  model.addAttribute("msg","无效操作,该账号已激活过!");
                  model.addAttribute("target","/index");
      
              }else{
                  model.addAttribute("msg","激活失败,您提供的激活码不正确!");
                  model.addAttribute("target","/index");
              }
              return "/site/operate-result";
          }
    • 对login界面做的声明(controller)的处理(html文件)
          @RequestMapping(path = "/login", method = RequestMethod.GET)
          public String getLoginPage(){
              return "site/login";
          }

      login.html 引入模板,并做常规修改。同时在index.html中,添加登录界面连接。

          <a class="nav-link" th:href="@{login}">登录</a>
  • 遇到的各种问题:

    • This application has no explicit mapping for /error。 There was an unexpected error (type=Not Found, status=404). No message available
      错误原因 :多写了html <a class="nav-link" th:href="@{login.html}">登录</a>  应该为 <a class="nav-link" th:href="@{login}">登录</a> 

    • 点击邮箱的连接无法跳转正确的界面。(其实是第二大部的错误)
      ——url的对应拼错了。在Service中使用的是  context.setVariable("key",url);   而在对应的HTML中采用的是  <a th:href="${url}">此链接</a>,   这样就导致按照url索引出来的值为null。无法进行跳转。更改Service中的变量  context.setVariable("url",url);   就可以完成跳转。

原文地址:https://www.cnblogs.com/codinghard/p/14823737.html