文章目录
开发注册功能
一次注册请求拆分成三次请求:
第一次请求 用户访问注册页面,服务器接受请求返回注册页面;
第二次请求 用户填写表单,提交给服务器,服务器接受此次请求,调用对应的服务来处理用户提交的数据,如果数据有误(用户名存在,邮箱存在)就返回注册页面让用户重新填写,如果数据无误,则向用户发送一封激活邮件;
第三次请求 用户若数据有误,重复第二次请求 如果无误,点击激活邮件,再次访问服务器,服务器对其进行验证,(看用户是否存在,激活码是否正确)正确则激活,并且返回到登录页面 ,激活错误或者重复提交则返回到注册页面;
第一次请求 用户访问注册页面
1、编写loginController来处理请求,返回注册页面
- 修改注册页面,使之能被Thymeleaf引擎解析,修改声明,相对路径
@Controller
public class LoginController {
@RequestMapping(value = "/register",method = RequestMethod.GET)
public String getRegister() {
return "/site/register";
}
}
2、修改注册页面和主页,使用Thymeleaf语法
-
修改路径 把相对路径用@{}包起来
-
修改主页的首页和注册的路径 提取头部复用 增加th:fragment 取一个别名 在register页面中引用提取的头部
-
<header class="bg-dark sticky-top" th:fragment="header">
<header class="bg-dark sticky-top" th:replace="index::header">
引入jar包,生成随机字符串等处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hnrWemge-1645443671426)(C:\Users\XL\AppData\Roaming\Typora\typora-user-images\image-20220221095932254.png)]
修改项目域名,暂时为本地路径
#community
community.path.domain=http://localhost:8080
建立一个工具类,方便生成随机字符串和处理加密的工作
- MD5加密因为会生成一个固定的加密后的字符串,不安全,所以采用在用户密码后拼接一共字符串的方法
public class CommunityUtil {
//生成随机字符串
public static String generateUUID()
{
//把生成的字符串的-替换成空格
return UUID.randomUUID().toString().replaceAll("-","");
}
//MD5加密加一段随机字符串提高安全性
public static String MD5(String key)
{
//如果key为空则返回空
if(StringUtils.isBlank(key))
{
return null;
}
//加密成十六进制字符串返回
return DigestUtils.md5DigestAsHex(key.getBytes());
}
}
第二次请求 用户填写表单
编写UserService对注册业务进行处理
-
编写注册方法 返回类型为Map 用来保存处理的结果
-
对账号为空,密码错误,邮箱已经被注册等问题进行判断提示
-
执行注册,设置用户的详细信息 userid设置的是自增长,不需要手动添加
-
最后调用UserMapper把用户信息插入到数据库中
@Service public class UserService { @Autowired(required = false) private UserMapper userMapper; //注入域名和工程路径 @Value("${community.path.domain}") private String domain; @Value("${server.servlet.context-path}") private String contextPath; @Autowired private TemplateEngine templateEngine; @Autowired private MailClient mailClient; public User queryUserById(int userId) { return userMapper.queryById(userId); } //注册业务 public Map<String,Object> register(User user) { Map<String,Object> map=new HashMap<>(); if(user==null) { throw new IllegalArgumentException("用户信息不能为空"); } //验证用户名是否已经存在 if(userMapper.queryByName(user.getUsername())!=null) { map.put("usernameMsg","用户名已经存在"); return map; } //验证邮箱是否已经存在 if(userMapper.queryByEmail(user.getEmail())!=null) { map.put("emailMsg","邮箱已经存在"); return map; } //注册用户 //保存用户随机字符串 截取5个 user.setSalt(StringUtils.substring(CommunityUtil.generateUUID(),5)); //保存密码 String key=user.getPassword()+user.getSalt(); user.setPassword(CommunityUtil.MD5(key)); user.setType(0); user.setStatus(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/community/activation/101/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; } }
编写Controller处理用户提交数据的请求
@RequestMapping(value = "/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("url","/index");
return "/site/operate-result";
}else {
model.addAttribute("usernameMsg", map.get("usernameMsg"));
model.addAttribute("passwordMsg", map.get("passwordMsg"));
model.addAttribute("emailMsg", map.get("emailMsg"));
return "/site/register";
}
}
修改表单数据
- 修改表单提交路径
- 给每一个框取一个name,声明数据的名字,name要和controller中的User属性名对应,SpringMvc基于同名原则把值传为User。username
- 注册没有成功,处理错误消息
- 如果是错误返回主页,这时主页就需要显示刚才已经填好的信息;如果是直接访问,就显示空
- 账号有问题返回账号错误信息,密码,邮箱同理
- 错误信息是否显示依靠样式is-invalid 因此需要动态拼接
<!-- 内容 -->
<div class="main">
<div class="container pl-5 pr-5 pt-3 pb-3 mt-3 mb-3">
<h3 class="text-center text-info border-bottom pb-3">注 册</h3>
<form class="mt-5" method="post" th:action="@{/register}">
<div class="form-group row">
<label for="username" class="col-sm-2 col-form-label text-right">账号:</label>
<div class="col-sm-10">
<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>
</div>
</div>
第三次请求 激活注册账号
定义常量接口
usersERVICES实现接口
public interface CommunityConstant {
/**
* 激活成功
*/
int ACTIVATION_SUCCESS = 0;
/**
* 重复激活
*/
int ACTIVATION_REPEAT = 1;
/**
* 激活失败
*/
int ACTIVATION_FAILURE = 2;
}
- 先从数据库中获取该user的信息
- 如果其状态status==1表示已经激活,返回重复激活
- 否则激活码正确 更新用户状态为已经激活
- 否则激活失败
//激活业务
public int activation(int userId,String code)
{
User user = userMapper.queryById(userId);
if(user.getStatus()==1)
{
return ACTIVATION_REPEAT;
}else if(user.getActivationCode().equals(code))
{
userMapper.UpdateStatus(userId,1);
return ACTIVATION_SUCCESS;
}else {
return ACTIVATION_FAILURE;
}
}
- 编写激活controller方法
- @PathVariable 从路径中获取变量值
- 调用service的激活方法根据返回值往modle里放入不同的信息 和跳转值
// http://localhost:8080/community/activation/101/code
@RequestMapping(path = "/activation/{userId}/{code}", method = RequestMethod.GET)
public String activation(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("url", "/login");
} else if (result == ACTIVATION_REPEAT) {
model.addAttribute("msg", "无效操作,该账号已经激活过了!");
model.addAttribute("url", "/index");
} else {
model.addAttribute("msg", "激活失败,您提供的激活码不正确!");
model.addAttribute("url", "/index");
}
return "/site/operate-result";
}
编写方法处理login请求
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String getLogin() {
return "/site/login";
}