springboot项目注册接口
基于eclipse工具上的
一、Controller层
package cn.kooun.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cn.kooun.pojo.params.UserLoginParam;
import cn.kooun.pojo.params.UserRegisterParam;
import cn.kooun.service.UserService;
/**
* 用户Controller
* @author HuangJingNa
* @date 2019年12月20日 上午9:21:38
*
*/
@RestController //@Controller+@Responsebody
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
/**
* 用户注册
* @author HuangJingNa
* @date 2019年12月20日 上午9:23:15
*
* @return
* 客户端请求的数据一般封装在自定义的pojo类中(XxxParam)
*/
/* 业务需求
* 1.校验数据
* 校验账号(非空、长度、唯一性)
* 校验密码(非空、长度、格式)
* 2.数据库操作(插入操作)
* 3.将数据响应给客户端/页面
*/
@GetMapping("register")
public Object register(UserRegisterParam userRegisterParam) {
return userService.register(userRegisterParam);
}
}
注册接口参数封装类UserRegisterParam
package cn.kooun.pojo.params;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* 注册接口参数封装
* @author HuangJingNa
* @date 2019年12月20日 上午9:28:47
*
*/
@Setter
@Getter
@ToString
public class UserRegisterParam {
/**账号名称*/
private String username;
/**账号密码*/
private String password;
}
二、service层
业务层:主要分为三步走:
1. 数据校验
2. 数据库的相关操作
3. 返回响应结果给客户端/页面
一般多次创建实例的,可以使用工厂模式
加密:使用Md5(较易破解),可以加入“盐”混合加密,越复杂越难破解
一般的标准校验(非空、长度、格式的判断)放在数据校验工具类中
操作数据库的代码较多,一般封装成一个方法(选中按alt+shift+M可以生成方法)
package cn.kooun.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import cn.kooun.common.CheckUtils;
import cn.kooun.common.Md5Utils;
import cn.kooun.common.UuidUtils;
import cn.kooun.common.result.Result;
import cn.kooun.common.result.ResultUtils;
import cn.kooun.mapper.UserMapper;
import cn.kooun.pojo.params.UserLoginParam;
import cn.kooun.pojo.params.UserRegisterParam;
import cn.kooun.pojo.table.User;
/**
* 用户service
* @author HuangJingNa
* @date 2019年12月20日 上午9:29:25
*
*/
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
/**
* 注册业务
* @author HuangJingNa
* @date 2019年12月20日 上午9:30:21
*
* @param userRegisterParam
* @return
*/
public Object register(UserRegisterParam userRegisterParam) {
//数据校验
Object result = this.checkRegister(userRegisterParam);
if(result != null) {
return result;
}
//插入数据库
//由于字段可能会发生变化,插入需要动态生成(使mapper类继承通用mapper)
this.saveRegister(userRegisterParam);
//返回友好提示,注册成功(使用工具类)
return ResultUtils.success("注册成功~", Result.JUMP_LOGIN);
}
/**
* 将账号密码插入数据库中
* @author HuangJingNa
* @date 2019年12月20日 下午3:33:48
*
* @param userRegisterParam
*/
private void saveRegister(UserRegisterParam userRegisterParam) {
User user = new User();
user.setId(UuidUtils.getUuid());
user.setUsername(userRegisterParam.getUsername());
user.setPassword(Md5Utils.getPassword(
userRegisterParam.getPassword(),
userRegisterParam.getUsername()));
user.setNickName("kooun_" + user.getId());
user.setType(1);
userMapper.insertSelective(user);
}
/**
* 注册业务数据校验
* @author HuangJingNa
* @date 2019年12月20日 下午2:43:37
*
* @param userRegisterParam
* @return
*/
private Object checkRegister(UserRegisterParam userRegisterParam) {
String username = userRegisterParam.getUsername();
String password = userRegisterParam.getPassword();
//校验账号
if(!CheckUtils.checkUsername(username)) {
return ResultUtils.error("账号不合法,请输入6-16个字母和数字的组合");
}
//校验账号是否存在
if(userMapper.isExistUserNameByUsername(username)) {
return ResultUtils.error("账号已被占用了~");
}
//校验密码
if(!CheckUtils.checkPassword(password)) {
return ResultUtils.error("密码不合法,请输入6-20个字母和数字的组合");
}
return null;
}
}
数据校验工具类CheckUtils
package cn.kooun.common;
import org.springframework.util.StringUtils;
/**
* 数据校验工具
* @author HuangJingNa
* @date 2019年12月20日 下午2:49:58
*
*/
public class CheckUtils {
/**
* 校验账户数据
* @author HuangJingNa
* @param username
* @date 2019年12月20日 下午2:50:11
*
* @return
*/
public static boolean checkUsername(String username) {
boolean flag = true;
if(StringUtils.isEmpty(username)) {
return !flag;
}
if(!username.matches("[0-9a-zA-Z]{6,16}")) {
return !flag;
}
return flag;
}
/**
* 校验密码数据
* @author HuangJingNa
* @date 2019年12月20日 下午3:28:00
*
* @param password
* @return
*/
public static boolean checkPassword(String password) {
boolean flag = true;
if(StringUtils.isEmpty(password)) {
return !flag;
}
if(!password.matches("[0-9a-zA-Z]{6,20}")) {
return !flag;
}
return flag;
}
}
响应消息封装工具类
响应返回的数据Result
package cn.kooun.common.result;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* 通用响应数据模型
* @author HuangJingNa
* @date 2019年12月20日 下午2:57:50
*
*/
@Setter
@Getter
@ToString
public class Result {
/*
* {
* status: "success/error",
* message: "友好提示消息",
* result: "业务数据",
* jump: "跳转标记=> index(首页),login(登录页)"
* }
*/
/**成功状态*/
public static final String STATUS_SUCCESS = "success";
/**错误状态*/
public static final String STATUS_ERROR = "error";
/**登录页跳转*/
public static final String JUMP_LOGIN = "login";
/**首页跳转*/
public static final String JUMP_INDEX = "index";
/**响应状态*/
private String status;
/**响应消息*/
private String message;
/**响应数据*/
private Object result;
/**跳转标识*/
private String jump;
}
工具类
package cn.kooun.common.result;
import cn.kooun.common.factory.ErrorResultFactory;
import cn.kooun.common.factory.SuccessResultFactory;
/**
* 业务响应标准类
* @author HuangJingNa
* @date 2019年12月20日 下午2:54:48
*
*/
public class ResultUtils {
/**
* 业务成功响应
* @author HuangJingNa
* @date 2019年12月20日 下午2:56:45
*
* @param string
* @return
*/
public static Object success(String message) {
SuccessResult successResult = SuccessResultFactory.getInstance();
successResult.setMessage(message);
return successResult;
}
/**
* 业务成功响应
* @author HuangJingNa
* @date 2019年12月20日 下午2:56:45
*
* @param string
* @return
*/
public static Object success(String message, String jump) {
SuccessResult successResult = SuccessResultFactory.getInstance();
successResult.setMessage(message);
successResult.setJump(jump);
return successResult;
}
/**
* 业务错误响应
* @author HuangJingNa
* @date 2019年12月20日 下午3:30:09
*
* @param string
* @return
*/
public static Object error(String message) {
ErrorResult errorResult = ErrorResultFactory.getInstance();
errorResult.setMessage(message);
return errorResult;
}
/**
* 业务成功响应
* @author HuangJingNa
* @date 2019年12月20日 下午7:57:51
*
* @param string
* @param jumpIndex
* @param ticket
* @return
*/
public static Object success(
String message,
String jump,
Object result) {
SuccessResult successResult = SuccessResultFactory.getInstance();
successResult.setMessage(message);
successResult.setJump(jump);
successResult.setResult(result);
return successResult;
}
}
成功数据封装
package cn.kooun.common.result;
/**
* 成功业务封装数据
* @author HuangJingNa
* @date 2019年12月20日 下午3:01:58
*
*/
public class SuccessResult extends Result{
{
this.setStatus(Result.STATUS_SUCCESS);
}
}
错误数据封装
package cn.kooun.common.result;
/**
* 错误业务封装数据
* @author HuangJingNa
* @date 2019年12月20日 下午3:01:58
*
*/
public class ErrorResult extends Result{
{
this.setStatus(Result.STATUS_ERROR);
}
}
由于要多次创建对象,则使用工厂模式
抽象工厂
package cn.kooun.common.factory;
/**
* 响应结果抽象工厂
* @author HuangJingNa
* @date 2019年12月20日 下午3:11:37
*
*/
public interface Factory<T> {
/**
* 创建具体实例
* @author HuangJingNa
* @date 2019年12月20日 下午3:12:50
*
* @return
*/
T newInstance();
}
成功响应实例工厂
package cn.kooun.common.factory;
import cn.kooun.common.result.SuccessResult;
/**
* 成功响应数据工厂
* @author HuangJingNa
* @date 2019年12月20日 下午3:31:15
*
*/
public class SuccessResultFactory implements Factory<SuccessResult> {
//懒汉式
private static SuccessResultFactory successResultFactory;
static{
if(successResultFactory == null) {
successResultFactory = new SuccessResultFactory();
}
}
/**
* 创建具体实例
*/
public SuccessResult newInstance() {
return new SuccessResult();
}
/**
* 创建具体实例
*/
public static SuccessResult getInstance() {
return new SuccessResultFactory().newInstance();
}
}
失败响应实例工厂
package cn.kooun.common.factory;
import cn.kooun.common.result.ErrorResult;
/**
* 错误响应数据工厂
* @author HuangJingNa
* @date 2019年12月20日 下午3:31:07
*
*/
public class ErrorResultFactory implements Factory<ErrorResult> {
private static ErrorResultFactory errorResultFactory;
static{
if(errorResultFactory == null) {
errorResultFactory = new ErrorResultFactory();
}
}
/**
* 创建具体实例
*/
public ErrorResult newInstance() {
return new ErrorResult();
}
/**
* 创建具体实例
*/
public static ErrorResult getInstance() {
return new ErrorResultFactory().newInstance();
}
}
三、使用逆向工程生成pojo类和mapper接口及mapper.xml文件
逆向工程的生成:https://www.jianshu.com/p/c61f0bf1efe0
数据库创建表通常都有的字段封装到一个基础表类中(BaseTable),要实现序列化,便于客户端使用json数据(要求实现序列化以及拥有序列化id)响应
package cn.kooun.pojo.table.base;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* 基础表
* 需要实现序列化,给与一个序列化id
* @author HuangJingNa
* @date 2019年12月20日 下午2:30:37
*
*/
@Setter
@Getter
@ToString
public class BaseTable implements Serializable{
//由于createTime和updateTime每次创建对象的时候需要赋值
//可以使用构造代码块,避免每次创建对象时都需要set
{
this.setCreateTime(new Date());
this.setUpdateTime(new Date());
}
private static final long serialVersionUID = 8533571383425561865L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY,generator="Mysql")
private String id;
//@Column(name = "create_time")//告诉通用mapper此变量对应表的字段名
//这里开启了驼峰命名,可以省略以上步骤
private Date createTime;
private Date updateTime;
}
pojo类:User.java
package cn.kooun.pojo.table;
import javax.persistence.Table;
import cn.kooun.pojo.table.base.BaseTable;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* 用户表
* @author HuangJingNa
* @date 2019年12月20日 下午2:32:09
* 1.通过lombok日志包可以通过注解动态生成get&set方法,但是需要注明是哪一张表,方便映射
* 2.开启驼峰命名,可以在类和数据库中将两个单词通过_连接,改为小驼峰命名,
* 同时可以省略注解@Column(name = "create_time")
* 3.主键需要注明,以及自动增长
*/
@Setter
@Getter
@ToString
//@Data //@Setter+@Getter+@ToString等的集合体
@Table(name = "u_user")
public class User extends BaseTable{
private static final long serialVersionUID = -2649200110993098831L;
/**账号名称*/
private String username;
/**账号密码*/
private String password;
/**账号类型*/
private Integer type;
/**账号昵称*/
private String nickName;
}
mapper接口:UserMapper.java
package cn.kooun.mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import cn.kooun.pojo.table.User;
import tk.mybatis.mapper.common.Mapper;
/**
* 用户mapper
* 1.需要继承通过Mapper的泛型类,可以获取其本身拥有的增删改查操作
* @author HuangJingNa
* @date 2019年12月20日 下午3:44:22
*
*/
public interface UserMapper extends Mapper<User>{
/**
* 判断该用户是否存在
* @author HuangJingNa
* @date 2019年12月20日 下午3:44:02
*
* @param username
* @return
*/
@Select("SELECT " +
" CASE COUNT(u.id) WHEN 0 THEN 0 ELSE 1 END" +
" FROM u_user u" +
" WHERE u.username = #{username}")
boolean isExistUserNameByUsername(@Param("username")String username);
}
mapper.xml文件:UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.kooun.mapper.UserMapper">
</mapper>