用户表
CREATE TABLE `t_user` (
`uid` int NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` varchar(20) NOT NULL COMMENT '用户名',
`password` char(32) NOT NULL COMMENT '密码',
`md5password` varchar(255) DEFAULT NULL,
`salt` char(36) DEFAULT NULL COMMENT '盐值',
`phone` varchar(20) DEFAULT NULL COMMENT '电话号码',
`email` varchar(30) DEFAULT NULL COMMENT '电子邮箱',
`gender` int DEFAULT NULL COMMENT '性别:0-女,1-男',
`avatar` varchar(50) DEFAULT NULL COMMENT '头像',
`is_delete` int DEFAULT NULL COMMENT '是否删除:0-未删除,1-已删除',
`created_user` varchar(20) DEFAULT NULL COMMENT '日志-创建人',
`created_time` datetime DEFAULT NULL COMMENT '日志-创建时间',
`modified_user` varchar(20) DEFAULT NULL COMMENT '日志-最后修改执行人',
`modified_time` datetime DEFAULT NULL COMMENT '日志-最后修改时间',
PRIMARY KEY (`uid`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb3;
后面的created_user ,created_time, modified_user, modified_time属性可以作为基类专门设定
package com.cy.store.entity;
import java.util.Date;
import java.util.Objects;
/**
创建用户的基类
*/
public class BaseEntity {
private String createdUser;
private Date createdTime;
private String modifiedUser;
private Date modifiedTime;
@Override
public String toString() {
return "BaseEntity{" +
"createdUser='" + createdUser + '\'' +
", createdTime=" + createdTime +
", modifiedUser='" + modifiedUser + '\'' +
", modifiedTime=" + modifiedTime +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BaseEntity)) return false;
BaseEntity that = (BaseEntity) o;
return Objects.equals(createdUser, that.createdUser) && Objects.equals(createdTime, that.createdTime) && Objects.equals(modifiedUser, that.modifiedUser) && Objects.equals(modifiedTime, that.modifiedTime);
}
@Override
public int hashCode() {
return Objects.hash(createdUser, createdTime, modifiedUser, modifiedTime);
}
public String getCreatedUser() {
return createdUser;
}
public void setCreatedUser(String createdUser) {
this.createdUser = createdUser;
}
public Date getCreatedTime() {
return createdTime;
}
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
public String getModifiedUser() {
return modifiedUser;
}
public void setModifiedUser(String modifiedUser) {
this.modifiedUser = modifiedUser;
}
public Date getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(Date modifiedTime) {
this.modifiedTime = modifiedTime;
}
}
然后User类继承基类创建,置于bean目录当中
package com.cy.store.bean;
import com.cy.store.entity.BaseEntity;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Objects;
/**
* 用户类的实体类
* 继承基类
* SpringBoot约定大于配置
*/
//@Component
public class User extends BaseEntity implements Serializable {
private Integer uid;
private String username;
private String password;
private String md5Password;
private String salt;//盐值,加密使用
private String phone;
private String email;
private Integer gender;//性别,男1女0
private String avatar;//头像
private Integer isDelete;//是否删除,0未删除,1已删除
/*
public User() {
}
*/
public User(Integer uid, String username, String password, String md5Password, String salt, String phone, String email, Integer gender, String avatar, Integer isDelete) {
this.uid = uid;
this.username = username;
this.password = password;
this.md5Password = md5Password;
this.salt = salt;
this.phone = phone;
this.email = email;
this.gender = gender;
this.avatar = avatar;
this.isDelete = isDelete;
}
@Override
public String toString() {
return "User{" +
"uid=" + uid +
", username='" + username + '\'' +
", password='" + password + '\'' +
", md5Password='" + md5Password + '\'' +
", salt='" + salt + '\'' +
", phone='" + phone + '\'' +
", email='" + email + '\'' +
", gender=" + gender +
", avatar='" + avatar + '\'' +
", isDelete=" + isDelete +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
if (!super.equals(o)) return false;
User user = (User) o;
return Objects.equals(uid, user.uid) && Objects.equals(username, user.username) && Objects.equals(password, user.password) && Objects.equals(md5Password, user.md5Password) && Objects.equals(salt, user.salt) && Objects.equals(phone, user.phone) && Objects.equals(email, user.email) && Objects.equals(gender, user.gender) && Objects.equals(avatar, user.avatar) && Objects.equals(isDelete, user.isDelete);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), uid, username, password, md5Password, salt, phone, email, gender, avatar, isDelete);
}
public String getMd5Password() {
return md5Password;
}
public void setMd5Password(String md5Password) {
this.md5Password = md5Password;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public Integer getIsDelete() {
return isDelete;
}
public void setIsDelete(Integer isDelete) {
this.isDelete = isDelete;
}
}
首先创建一个mapper接口,便于springboot注入,接口里只有方法名和其返回值
package com.cy.store.mapper;
import com.cy.store.bean.User;
/**
* 用户模块的持久层接口
*/
//@Mapper
public interface UserMapper {
/**
* 插入用户的数据
* @param user 用户数据
* @return 受影响的行数(增删改查受影响行数返回值
*/
Integer insert(User user);
/**
* 根据用户名来查找用户的数据
* @param username 用户名
* @return 如果找到对应用户返回这个用户数据,没找到返回null
*/
User findByUsername(String username);
}
然后再进行mapper.xml的编写,sql语句放在这个模块中
INSERT INTO t_user(
username,
password,
md5password,
salt,
phone,
email,
gender,
avatar,
is_delete,
created_user,
created_time,
modified_user,
modified_time
)VALUES (
#{username},
#{password},
#{md5Password},
#{salt},
#{phone},
#{email},
#{gender},
#{avatar},
#{isDelete},
#{createdUser},
#{createdTime},
#{modifiedUser},
#{modifiedTime}
)
首先编写IUserService接口,只写方法,之后的service实现类都可以继承当前接口
package com.cy.store.service;
import com.cy.store.bean.User;
public interface IUserService{
void reg(User user);
}
然后编写Service的实现类,即UserServiceImpl
package com.cy.store.service.impl;
import com.cy.store.bean.User;
import com.cy.store.mapper.UserMapper;
import com.cy.store.service.IUserService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.UsernameDuplicatedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import javax.xml.crypto.Data;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.UUID;
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private UserMapper userMapper;
@Override
public void reg(User user) {
//通过传来的user获取username
String username = user.getUsername();
//调用findByUsername(username)判断用户是否注册过
User result = userMapper.findByUsername(username);
//判断结果集不是null则抛出用户名被占用的异常
if (result != null){
//抛出异常
throw new UsernameDuplicatedException("用户名被占用");
}
//密码加密处理实现:md5算法的形式
//串 + password + 串 ----md5算法进行加密,连续加载三次
//这个串是随机生成的,也叫做盐值
String oldPassword = user.getPassword();
//获取盐值
String salt = UUID.randomUUID().toString().toUpperCase();//全大写
//将密码和盐值作为一个整体进行加密处理
String md5Password = getMD5Password(oldPassword, salt);
//将加密之后的密码重新补全到user对象中
user.setSalt(salt);//盐值栏存盐值的记录
user.setMd5Password(md5Password);
//存md5的密码
//忽略了原有密码的安全强度,提升了数据的安全性
//补全数据,is_delete设为0
user.setIsDelete(0);
//补全数据:四个日志字段信息
user.setCreatedUser(user.getUsername());
user.setModifiedUser(user.getUsername());
Date date = new Date();
user.setCreatedTime(date);
user.setModifiedTime(date);
//执行注册业务功能的实现
Integer rows = userMapper.insert(user);
if (rows != 1){
throw new InsertException("用户注册过程中出现了未知的异常");
}
}
/**
* 定义一个md5算法的加密
* */
private String getMD5Password(String password,String salt){
String s = "";
for (int i = 0; i < 3; i++) {
//MD5的加密算法加密三次
s=DigestUtils.md5DigestAsHex((salt+password+salt).getBytes()).toUpperCase();
}
return s;
}
}
注:这里有关盐值了解了一些
在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”。
加密方式即在密码的前后都加上随机的盐值,然后对生成的字符串进行md5的加密操作,一般连续加密三次。
最后是三个异常的继承实现
package com.cy.store.service.ex;
/**
* 数据插入过程中所产生的异常
*/
public class InsertException extends ServiceException{
public InsertException() {
}
public InsertException(String message) {
super(message);
}
public InsertException(String message, Throwable cause) {
super(message, cause);
}
public InsertException(Throwable cause) {
super(cause);
}
public InsertException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package com.cy.store.service.ex;
/**
* 业务层异常基类
*/
public class ServiceException extends RuntimeException{
public ServiceException() {
super();
}
public ServiceException(String message) {
super(message);
}
public ServiceException(String message, Throwable cause) {
super(message, cause);
}
public ServiceException(Throwable cause) {
super(cause);
}
protected ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package com.cy.store.service.ex;
/**
* 用户名被占用的异常
*/
public class UsernameDuplicatedException extends ServiceException{
public UsernameDuplicatedException() {
super();
}
public UsernameDuplicatedException(String message) {
super(message);
}
public UsernameDuplicatedException(String message, Throwable cause) {
super(message, cause);
}
public UsernameDuplicatedException(Throwable cause) {
super(cause);
}
protected UsernameDuplicatedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package com.cy.store.controller;
import com.cy.store.bean.User;
import com.cy.store.service.IUserService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.UsernameDuplicatedException;
import com.cy.store.service.impl.UserServiceImpl;
import com.cy.store.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
//@Controller
@RestController//组合注解,相当于 @Controller + @ResponseBody
@RequestMapping("/users")
public class UserController extends BaseController{
@Autowired
private UserServiceImpl userService;
@RequestMapping("reg")
//@ResponseBody//表示此方法的响应结果以json的格式进行数据的响应给到前端
public JsonResult req(User user){
//创建响应结果对象
//JsonResult result = new JsonResult<>();
/**
* 如果类很多的话,会重复以下代码多次
* 则可以抽离一个父类,在父类中统一处理关于异常的相关操作
* 编写一个BaseController,让当前类继承基类
* */
try {
userService.reg(user);
result.setState(200);
result.setMessage("用户注册成功");
}catch (UsernameDuplicatedException e){
result.setState(404);
result.setMessage("用户名被占用");
}catch (InsertException e){
result.setState(500);
result.setMessage("注册时产生未知的异常");
}
return result;
}
}
这样处理每一个方法都需要进行异常的处理,所以可以创建一个controller基类,专门用来对异常的处理
package com.cy.store.controller;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.ServiceException;
import com.cy.store.service.ex.UsernameDuplicatedException;
import com.cy.store.util.JsonResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* 用这个类表示控制层类的基类
* */
public class BaseController {
/* 操作成功的状态码 */
public static final int OK = 200;
/**
* @ExceptionHandler 用于统一处理抛出的异常
* 请求处理方法,这个方法的返回值就是要传递给前端的数据
* 自动将异常对象传递给此方法的参数列表上
* 当前项目中产生了异常,被统一拦截到此方法中,
* 这个方法此时就充当请求处理方法,方法的返回值给到前端
*
*/
@ExceptionHandler({ServiceException.class})
public JsonResult handleException(Throwable e){
JsonResult result = new JsonResult<>(e);
if (e instanceof UsernameDuplicatedException){
result.setState(404);
result.setMessage("用户名被占用");
}else if (e instanceof InsertException){
result.setState(500);
result.setMessage("注册时产生未知的异常");
}
return result;
}
}
添加基类后原代码变为
package com.cy.store.controller;
import com.cy.store.bean.User;
import com.cy.store.service.IUserService;
import com.cy.store.service.ex.InsertException;
import com.cy.store.service.ex.UsernameDuplicatedException;
import com.cy.store.service.impl.UserServiceImpl;
import com.cy.store.util.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
//@Controller
@RestController//组合注解,相当于 @Controller + @ResponseBody
@RequestMapping("/users")
public class UserController extends BaseController{
@Autowired
private UserServiceImpl userService;
@RequestMapping("reg")
//@ResponseBody//表示此方法的响应结果以json的格式进行数据的响应给到前端
public JsonResult req(User user){
/**
* 继承基类后代码:
* 如果遇到异常会被基类的 handleException处理
* 加了@ExceptionHandler注解后悔自动将异常对象传递给此方法的参数列表上
* */
userService.reg(user);
return new JsonResult<>(OK);
}
}
JsonResult类:用来前后端交互,存放返回给前端的各种信息等
package com.cy.store.util;
import java.io.Serializable;
/**
* Json格式的数据进行响应
* */
public class JsonResult implements Serializable {
/* 状态码 */
private Integer state;
/* 描述信息 */
private String message;
/* 响应数据 */
private E data;
public JsonResult() {
}
public JsonResult(Integer state) {
this.state = state;
}
public JsonResult(Throwable e) {
this.message = e.getMessage();
}
public JsonResult(Integer state, E data) {
this.state = state;
this.data = data;
}
public JsonResult(Integer state, String message, E data) {
this.state = state;
this.message = message;
this.data = data;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public E getData() {
return data;
}
public void setData(E data) {
this.data = data;
}
}