首先,为了业务方法返回错误信息格式的统一,我们在com.ql.reader.service.exception包下创建一个自定义异常:
package com.ql.reader.service.exception;
/**
* BussinessException业务逻辑异常
*/
public class BussinessException extends RuntimeException{
private String code;
private String msg;
public BussinessException(String code, String msg){
super(msg);
this.code = code;
this.msg = msg;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
会员注册时需要对密码MD5加密存储,所以在com.ql.reader.utils包下创建MD5工具类
package com.ql.reader.utils;
import org.apache.commons.codec.digest.DigestUtils;
public class MD5Utils {
public static String md5Digest(String source, Integer salt){
char[] ca = source.toCharArray();
//混淆源数据
for (int i = 0; i < ca.length; i++) {
ca[i] = (char) (ca[i] + salt);
}
String target = new String(ca);
String md5 = DigestUtils.md5Hex(target);
return md5;
}
}
接下来开始写注册业务逻辑,在com.ql.reader.service包下创建会员业务接口,并且在com.ql.reader.service.impl包下创建它的实现类
package com.ql.reader.service;
import com.ql.reader.entity.Member;
public interface MemberService {
/**
* 会员注册,创建新会员
* @param username 用户名
* @param password 密码
* @param nickname 昵称
* @return 新会员对象
*/
public Member createMember(String username, String password, String nickname);
}
package com.ql.reader.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ql.reader.entity.Member;
import com.ql.reader.mapper.MemberMapper;
import com.ql.reader.service.MemberService;
import com.ql.reader.service.exception.BussinessException;
import com.ql.reader.utils.MD5Utils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Random;
@Service("memberService")
@Transactional
public class MemberServiceImpl implements MemberService {
@Resource
private MemberMapper memberMapper;
/**
* 会员注册,创建新会员
*
* @param username 用户名
* @param password 密码
* @param nickname 昵称
* @return 新会员对象
*/
public Member createMember(String username, String password, String nickname) {
QueryWrapper<Member> queryWrapper = new QueryWrapper<Member>();
queryWrapper.eq("username", username);
List<Member> memberList = memberMapper.selectList(queryWrapper);
//判断用户名是否已存在
if(memberList.size()>0){
throw new BussinessException("M01", "用户名已存在");
}
Member member = new Member();
member.setUsername(username);
member.setNickname(nickname);
int salt = new Random().nextInt(1000) + 1000;//盐值
String md5 = MD5Utils.md5Digest(password, salt);
member.setPassword(md5);
member.setSalt(salt);
member.setCreateTime(new Date());
memberMapper.insert(member);
return member;
}
}
在src/test/java/com/ql/reader/service/impl目录下生成测试用例,运行测试
package com.ql.reader.service.impl;
import com.ql.reader.service.MemberService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class MemberServiceImplTest {
@Resource
private MemberService memberService;
@Test
public void createMember() {
memberService.createMember("s123456", "123456", "测试");
}
}
测试成功
再次运行测试用例会报用户名存在异常,符合我们业务逻辑。
然后打开MemberController.java修改会员注册方法
@PostMapping("/registe")
@ResponseBody
public Map registe(String vc, String username, String password, String nickname, HttpServletRequest request){
//正确验证码
String verifyCode = (String) request.getSession().getAttribute("kaptchaVerifyCode");
//验证码对比
Map result = new HashMap();
if (vc==null || verifyCode==null || !vc.equalsIgnoreCase(verifyCode)){
result.put("code", "VC01");
result.put("msg", "验证码错误");
}else{
try {
memberService.createMember(username, password, nickname);
result.put("code", "0");
result.put("msg", "success");
} catch (BussinessException e) {
e.printStackTrace();
result.put("code", e.getCode());
result.put("msg", e.getMsg());
}
}
return result;
}
运行项目,在浏览器中访问http://localhost:8080/register.html测试注册功能。
首先,打开MemberService.java接口添加登录检查方法
/**
* 登录检查
* @param username 用户名
* @param password 密码
* @return
*/
public Member checkLogin(String username, String password);
然后,在MemberServiceImpl.java中添加方法实现
/**
* 登录检查
*
* @param username 用户名
* @param password 密码
* @return
*/
public Member checkLogin(String username, String password) {
QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
Member member = memberMapper.selectOne(queryWrapper);
if(member==null){
throw new BussinessException("M02", "用户名不存在");
}
String md5 = MD5Utils.md5Digest(password, member.getSalt());
if(!md5.equals(member.getPassword())){
throw new BussinessException("M03", "输入密码有误");
}
return member;
}
然后打开MemberController.java添加跳转到登录页和登录验证的方法
@GetMapping("/login.html")
public ModelAndView showLogin(){
return new ModelAndView("/login");
}
@PostMapping("/check_login")
@ResponseBody
public Map checkLogin(String vc, String username, String password, HttpSession session){
//正确验证码
String verifyCode = (String)session.getAttribute("kaptchaVerifyCode");
//验证码对比
Map result = new HashMap();
if (vc==null || verifyCode==null || !vc.equalsIgnoreCase(verifyCode)){
result.put("code", "VC01");
result.put("msg", "验证码错误");
}else{
try {
Member member = memberService.checkLogin(username, password);
session.setAttribute("loginMember", member);
result.put("code", "0");
result.put("msg", "success");
} catch (BussinessException e) {
e.printStackTrace();
result.put("code", e.getCode());
result.put("msg", e.getMsg());
}
}
return result;
}
前端代码为:在src/main/webapp/WEB-INF/ftl目录下创建登录页login.ftl
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>会员登录-书评网title>
<meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1.0,user-scalable=no">
<link rel="stylesheet" href="http://cdn.itlaoqi.com./resources/bootstrap4/css/bootstrap.css">
<link rel="stylesheet" href="./resources/raty/lib/jquery.raty.css">
<script src="http://cdn.itlaoqi.com./resources/jquery.3.3.1.min.js">script>
<script src="http://cdn.itlaoqi.com./resources/bootstrap4/js/bootstrap.min.js">script>
<style>
.container {
padding: 0px;
margin: 0px;
}
.row {
padding: 0px;
margin: 0px;
}
.col- * {
padding: 0px;
}
.description p {
text-indent: 2em;
}
.description img {
width: 100%;
}
style>
head>
<body>
<div class="container ">
<nav class="navbar navbar-light bg-white shadow">
<ul class="nav">
<li class="nav-item">
<a href="/" style="color: #aaa;font-weight: bold">
书评网
a>
li>
ul>
nav>
<div class="container mt-2 p-2 m-0">
<form id="frmLogin">
<div class="passport bg-white">
<h4 class="float-left">会员登录h4>
<h6 class="float-right pt-2"><a href="/register.html">会员注册a>h6>
<div class="clearfix">div>
<div class="alert d-none mt-2" id="tips" role="alert">
div>
<div class="input-group mt-2 ">
<input type="text" id="username" name="username" class="form-control p-4" placeholder="请输入用户名"
aria-label="Username" aria-describedby="basic-addon1">
div>
<div class="input-group mt-4 ">
<input id="password" name="password" class="form-control p-4" placeholder="请输入密码" type="password"
aria-describedby="basic-addon1">
div>
<div class="input-group mt-4 ">
<div class="col-5 p-0">
<input type="text" id="verifyCode" name="vc" class="form-control p-4" placeholder="验证码">
div>
<div class="col-4 p-0 pl-2 pt-0">
<img id="imgVerifyCode" src="/verify_code"
style="width: 120px;height:50px;cursor: pointer">
div>
div>
<a id="btnSubmit" class="btn btn-success btn-block mt-4 text-white pt-3 pb-3">登 录a>
div>
form>
div>
div>
<script>
function showTips(isShow, css, text) {
if (isShow) {
$("#tips").removeClass("d-none")
$("#tips").hide();
$("#tips").addClass(css);
$("#tips").text(text);
$("#tips").fadeIn(200);
} else {
$("#tips").text("");
$("#tips").fadeOut(200);
$("#tips").removeClass();
$("#tips").addClass("alert")
}
}
function reloadVerifyCode(){
$("#imgVerifyCode").attr("src", "/verify_code?ts=" + new Date().getTime());
}
$("#imgVerifyCode").click(function () {
reloadVerifyCode();
});
$("#btnSubmit").click(function () {
var username = $.trim($("#username").val());
var regex = /^.{1,10}$/;
if (!regex.test(username)) {
showTips(true, "alert-danger", "用户名请输入正确格式(1-10位)");
return;
} else {
showTips(false);
}
var password = $.trim($("#password").val());
if (!regex.test(password)) {
showTips(true, "alert-danger", "密码请输入正确格式(1-10位)");
return;
} else {
showTips(false);
}
$btnReg = $(this);
$btnReg.text("正在处理...");
$btnReg.attr("disabled", "disabled");
$.ajax({
url: "/check_login",
type: "post",
dataType: "json",
data: $("#frmLogin").serialize(),
success: function (data) {
console.info(data);
if (data.code == "0") {
window.location = "/?ts=" + new Date().getTime();
} else {
showTips(true, "alert-danger", data.msg);
reloadVerifyCode();
$btnReg.text("登录");
$btnReg.removeAttr("disabled");
}
}
});
return false;
});
script>
body>
html>