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调用接口如下: