1.项目中我们经常遇到前端对输入框的非空校验 当然我们后端也要对此进行校验 ,以下是我自定义的demo,首先建两个工具类ValidateUtils,ValidNotEmpty ValidateUtils的代码如下:
package com.tone.utils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 入参校验 现只校验参数非空 其余待完善
*/
public class ValidateUtils {
private static final Logger log = LoggerFactory.getLogger(ValidateUtils.class);
/**
* 用于校验ValidNotEmpty 注解上的属性值是否为空
*
* @param object
* @throws Exception
*/
public static void nullFieldValidate(Object object) throws Exception {
if (null == object) {
throw new Exception("T can't be null");
}
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
Object fieldValue = runGetter(field, object);
boolean isAnnotationNotNull = field.isAnnotationPresent(ValidNotEmpty.class);
//获取对应注解
ValidNotEmpty validNotEmpty = field.getAnnotation(ValidNotEmpty.class);
//获取注解上的自定义值
String annotationFileName = "";
if (null != validNotEmpty) {
annotationFileName = validNotEmpty.fileName();
}
//属性上有validNotEmpty注解,并且值为空
if (isAnnotationNotNull && (null == fieldValue || StringUtils.isBlank(fieldValue.toString()))) {
if (StringUtils.isNotBlank(annotationFileName)) {
throw new Exception(annotationFileName + "不能为空");
} else {
throw new Exception(fieldName + "不能为空");
}
}
}
}
// 由于所有子类的属性都是private的,所以必须要找到属性的getter方法
public static Object runGetter(Field field, Object instance) {
for (Method method : instance.getClass().getDeclaredMethods()) {
//防止自定义非属性 getXXX方法影响
if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3))) {
if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase())) {
try {
// 找到对应的get方法
return method.invoke(instance);
} catch (IllegalAccessException | InvocationTargetException e) {
//执行错误
log.info("Could not determine method: " + method.getName());
System.out.println("Could not determine method: " + method.getName());
}
}
}
}
return null;
}
}
ValidNotEmpty的代码如下:
package com.tone.utils;
import javax.validation.Constraint;
import java.lang.annotation.*;
/**
* 自定义非空 注解
*/
@Documented
@Constraint(
validatedBy = {}
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME) //存活阶段
public @interface ValidNotEmpty {
/**
* 字段名称
*/
String fileName() default "";
}
2.自定义常量工具类,代码如下:
package com.tone.utils;
/**
* 常量工具类
*/
public class Contents {
//redis0-15 库分配用户管理使用0
public static int userIndexdb=0;
//redis0-15 库分配初始化数据存入使用1
public static int initResIndexdb=1;
//redis0-15 库分配初始化数据存入使用1
public static int initCaseIndexdb=2;
//redis0-15 库分配初始化数据存入使用1
public static int initSysRunIndexdb=3;
//流水号存放位置
public static int caseSerialIndexdb = 15;
//登陆缓存有效期 单位秒
public static int redisLoginTimeOut = 3600;
//APP登陆缓存有效期
public static int appRedisLoginTimeOut = 180000;
//流水号锁定时间
public static int caseSerialTimeOut = 3600;
//webToken md5加密
public static String keyStr = "longjin2019shanghai";
//redis角色资源权限key串
public static String roleResAuth = "resourcesAuth";
//业务请求成功
public static String requestSuccess = "200";
//业务请求失败
public static String requestFail = "201";
//用户未登陆或登陆超时
public static String noneLogin = "102";
//两次Token不一致
public static String authTokenFail = "103";
//Webtoken验证不正确
public static String authWebtokenFail = "105";
//删除失败
public static String deleteFail = "107";
//新增失败
public static String addFail = "108";
//更新失败
public static String updateFail = "109";
//没有访问权限
public static String requestAuthFail = "110";
public static String getMsg4Code(String code) {
String str = "未知";
switch (code) {
case "100":
str = "登录成功";
break;
case "101":
str = "用户名或密码不正确";
break;
case "102":
str = "用户未登陆或登陆超时";
break;
case "103":
str = "两次Token不一致";
break;
case "104":
str = "退出登录成功";
break;
case "105":
str = "Webtoken验证不正确";
break;
case "106":
str = "验证码输入不正确";
break;
case "107":
str = "删除失败";
break;
case "108":
str = "新增失败";
break;
case "109":
str = "更新失败";
break;
case "110":
str = "没有访问权限";
break;
case "111":
str = "前后端token不一致或已过期";
break;
case "200":
str = "请求处理成功";
break;
case "201":
str = "请求处理失败";
break;
default:
str = "其他";
break;
}
return str;
}
}
3.自定义全局异常处理,代码如下:
package com.tone.handle;
import javax.servlet.http.HttpServletRequest;
import com.tone.entity.Results;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* 全局异常处理
*/
@ControllerAdvice
public class GlobalDefaultExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalDefaultExceptionHandler.class);
@ExceptionHandler(Exception.class)
@ResponseBody
public Object defaultExceptionHandler(HttpServletRequest req, Exception e) {
log.error("发生未处理的异常={}",e.getMessage(),e);
Results r = new Results();
r.setStatusCode("202");
r.setStatusMsg(e.getMessage());
return r;
}
/**
* 获取异常堆栈信息
*
* @param throwable
* @return
*/
public static String getStrackTrace(Throwable throwable) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
try {
throwable.printStackTrace(pw);
return sw.toString();
} finally {
pw.close();
}
}
}
4.创建一个返回状态码的实体类 代码如下:
package com.tone.entity;
import com.tone.utils.Contents;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.HashMap;
import java.util.Map;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Results {
/**
* 返回码
*/
private String statusCode;
/**
* 返回消息
*/
private String statusMsg;
/**
* 请求的时间戳
*/
private String timestamp;
/**
* 返回请求内容
*/
private Map<String, Object> resMap;
public static Results success(String statusCode, String statusMsg, String timestamp, Map<String, Object> resMap) {
Results results = new Results(statusCode, statusMsg, timestamp, resMap);
return results;
}
public static Results success(String timestamp, Object data) {
Map<String, Object> resMap = new HashMap<>();
resMap.put("data", data);
return success(Contents.requestSuccess, Contents.getMsg4Code(Contents.requestSuccess), timestamp, resMap);
}
public static Results success(String timestamp) {
return success(Contents.requestSuccess, Contents.getMsg4Code(Contents.requestSuccess), timestamp, null);
}
public static Results fail(String statusCode, String statusMsg, String timestamp, Map<String, Object> resMap) {
Results results = new Results(statusCode, statusMsg, timestamp, resMap);
return results;
}
public static Results requestFail(String timestamp) {
return fail(Contents.requestFail, Contents.getMsg4Code(Contents.requestFail), timestamp, null);
}
/**
* msg自定义 返回
*
* @param timestamp
* @param msg
* @return
*/
public static Results requestFailMsg(String timestamp, String msg) {
return fail(Contents.requestFail, msg, timestamp, null);
}
public static Results addFail(String timestamp) {
return fail(Contents.addFail, Contents.getMsg4Code(Contents.addFail), timestamp, null);
}
public static Results updateFail(String timestamp) {
return fail(Contents.updateFail, Contents.getMsg4Code(Contents.updateFail), timestamp, null);
}
public static Results deleteFail(String timestamp) {
return fail(Contents.deleteFail, Contents.getMsg4Code(Contents.deleteFail), timestamp, null);
}
public static Results noLoginFail(String timestamp) {
return success(Contents.noneLogin, Contents.getMsg4Code(Contents.noneLogin), timestamp, null);
}
/**
* 根据条数以及type决定返回code,msg
*
* @param timestamp
* @param count
* @param type
* @return
*/
public static Results returnByCount(String timestamp, int count, String type) {
if (count >= 1) {
return success(timestamp);
} else if ("新增".equals(type) || "保存".equals(type)) {
return addFail(timestamp);
} else if ("修改".equals(type) || "更新".equals(type)) {
return updateFail(timestamp);
} else if ("删除".equals(type)) {
return deleteFail(timestamp);
} else {
return requestFail(timestamp);
}
}
}
5.创建一个表t_customer 实体类如下:
package com.tone.entity;
import com.tone.utils.ValidNotEmpty;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 客户信息(TCustomer)实体类
*
* @author makejava
* @since 2020-05-05 21:54:25
*/
@Data
public class Customer implements Serializable {
private static final long serialVersionUID = 209205595824413154L;
/**
* 主键id
*/
private Integer id;
/**
* 姓名
*/
@ValidNotEmpty(fileName = "姓名")
private String name;
/**
* 年龄
*/
@ValidNotEmpty(fileName = "年龄")
private Integer age;
/**
* 性别
*/
@ValidNotEmpty(fileName = "性别")
private Integer sex;
/**
* 教育
*/
@ValidNotEmpty(fileName = "教育")
private String education;
/**
* 创建时间
*/
private Date createTime;
}
6.dao层:
package com.tone.dao;
import com.tone.entity.Customer;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
/**
* 客户信息(TCustomer)表数据库访问层
*
* @author makejava
* @since 2020-05-05 21:54:26
*/
@Mapper
public interface CustomerMapper {
/**
* 新增数据
*
* @param customer 实例对象
* @return 影响行数
*/
@Insert("insert into t_customer(id,name,age,sex,education,create_time) values (null,#{name},#{age},#{sex},#{education},now())")
int save(Customer customer);
}
7.Customer的Service层:
package com.tone.service;
import com.tone.entity.Customer;
import java.util.List;
/**
* 客户信息(TCustomer)表服务接口
*
* @author makejava
* @since 2020-05-05 21:54:27
*/
public interface CustomerService {
/**
* 新增数据
*
* @param tCustomer 实例对象
* @return 实例对象
*/
int save(Customer tCustomer);
}
8.Customer的Service实现层:
package com.tone.service.impl;
import com.tone.dao.CustomerMapper;
import com.tone.entity.Customer;
import com.tone.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 客户信息(TCustomer)表服务实现类
*
* @author makejava
* @since 2020-05-05 21:54:27
*/
@Service
public class CustomerServiceImpl implements CustomerService {
@Resource
private CustomerMapper customerMapper;
/**
* 新增数据
*
* @param customer 实例对象
* @return 实例对象
*/
@Override
public int save(Customer customer) {
return this.customerMapper.save(customer);
}
}
9.Customer的Controller层:
package com.tone.controller;
import com.tone.entity.Customer;
import com.tone.entity.Results;
import com.tone.service.CustomerService;
import com.tone.utils.ValidateUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 客户信息(TCustomer)表控制层
*
* @author makejava
* @since 2020-05-05 21:54:28
*/
@RestController
@RequestMapping("/customer")
public class CustomerController {
/**
* 服务对象
*/
@Resource
private CustomerService customerService;
@GetMapping("save")
public Results save(@RequestBody Customer customer) throws Exception{
ValidateUtils.nullFieldValidate(customer);
int save = this.customerService.save(customer);
return Results.returnByCount(null,save,"新增");
}
}
10.通过postman调用接口如下: