访问注册界面:
三层(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>
-
找到对应首页的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>
因为头部(导航栏)在每个页面复用,每个都修改,十分繁琐。因此复用一下。在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()); } }
-
- 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; } } }
- 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>
-
(失败返回注册界面,提示信息 ,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>
- 注入UserService,按照逻辑写对应代码。
-
-
- 遇到的各种错误
-
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; }
- 在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; } }
- 在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); 就可以完成跳转。
-