配置类
分页插件配置类
@Configuration @MapperScan("com.project.smart_campus.mapper") public class MyConfig { /* * 分页插件 * */ @Bean public PaginationInterceptor paginationInterceptor(){ PaginationInterceptor paginationInterceptor=new PaginationInterceptor(); return paginationInterceptor; } }
Swagger2的配置类
引入依赖
<!--swagger--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.7.0</version> </dependency>
配置类
@Configuration @EnableSwagger2 public class Swagger2Config { @Bean public Docket webApiConfig(){ //添加head参数start List<Parameter> parameters=new ArrayList<>(); ParameterBuilder tokenPar=new ParameterBuilder(); tokenPar.name("userId") .description("测试用户1") .defaultValue("1") .modelRef(new ModelRef("string")) .parameterType("header") .required(false) .build(); parameters.add(tokenPar.build()); ParameterBuilder tmpPar = new ParameterBuilder(); tmpPar.name("userTempId") .description("测试用户2") .defaultValue("1") .modelRef(new ModelRef("string")) .parameterType("header") .required(false) .build(); parameters.add(tmpPar.build()); //添加head参数end return new Docket(DocumentationType.SWAGGER_2) .groupName("webApi") .apiInfo(webApiInfo()) .select() //可以测试请求头中:输入token //.apis(RequestHandlerSelectors.withClassAnnotation(ApiOperation.class)) .apis(RequestHandlerSelectors.basePackage("com.project.smart_campus.controller")) //过滤掉admin路径下的所有页面 //.paths(Predicates.and(PathSelectors.regex("/sms/.*"))) //过滤掉所有error或error.*页面 //.paths(Predicates.not(PathSelectors.regex("/error.*"))) .build() .globalOperationParameters(parameters); } private ApiInfo webApiInfo(){ return new ApiInfoBuilder() .title("网站-API文档") .description("本文档描述了网站微服务接口定义") .version("1.0") .contact(new Contact("sc", "http://mypoject.com", "123456@qq.com")) .build(); } private ApiInfo adminApiInfo(){ return new ApiInfoBuilder() .title("后台管理系统-API文档") .description("本文档描述了后台管理系统微服务接口定义") .version("1.0") .contact(new Contact("sc", "http://mypoject.com", "123456@qq.com")) .build(); } }
常用配置参数表
swagger常用注解表
工具类
验证码图片生成类
先定义验证码图片的基本属性,随后是验证码图片(获取)+验证码(生成+获取+绘制)
public class CreateVerifiCodeImage { /* * 定义长宽,字符大小,验证码,验证码图片 * */ private static int WIDTH = 90; private static int HEIGHT = 35; private static int FONT_SIZE = 20; private static char[] verifiCode; private static BufferedImage verifiCodeImage; /** * @description: 获取验证码图片 * @param: no * @return: java.awt.image.BufferedImage */ public static BufferedImage getVerifiCodeImage() { verifiCodeImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_BGR);// create a image Graphics graphics = verifiCodeImage.getGraphics(); verifiCode = generateCheckCode(); drawBackground(graphics); drawRands(graphics, verifiCode); graphics.dispose(); return verifiCodeImage; } /** * @description: 获取验证码 * @param: no * @return: char[] */ public static char[] getVerifiCode() { return verifiCode; } /** * @description: 随机生成验证码 * @param: no * @return: char[] */ private static char[] generateCheckCode() { String chars = "0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char[] rands = new char[4]; for (int i = 0; i < 4; i++) { int rand = (int) (Math.random() * (10 + 26 * 2)); rands[i] = chars.charAt(rand); } return rands; } /** * @description: 绘制验证码 * @param: g * @param: rands * @return: void */ private static void drawRands(Graphics g, char[] rands) { g.setFont(new Font("Console", Font.BOLD, FONT_SIZE)); for (int i = 0; i < rands.length; i++) { g.setColor(getRandomColor()); g.drawString("" + rands[i], i * FONT_SIZE + 10, 25); } } /** * @description: 绘制验证码图片背景 * @param: g * @return: void */ private static void drawBackground(Graphics g) { g.setColor(Color.white); g.fillRect(0, 0, WIDTH, HEIGHT); // 绘制验证码干扰点 for (int i = 0; i < 200; i++) { int x = (int) (Math.random() * WIDTH); int y = (int) (Math.random() * HEIGHT); g.setColor(getRandomColor()); g.drawOval(x, y, 1, 1); } } /** * @description: 获取随机颜色 * @param: no * @return: java.awt.Color */ private static Color getRandomColor() { Random ran = new Random(); return new Color(ran.nextInt(220), ran.nextInt(220), ran.nextInt(220)); } }
JwtHelper
token口令生成
public class JwtHelper { private static long tokenExpiration = 24*60*60*1000; private static String tokenSignKey = "123456"; //生成token字符串 public static String createToken(Long userId, Integer userType) { String token = Jwts.builder() .setSubject("YYGH-USER") .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)) .claim("userId", userId) // .claim("userName", userName) .claim("userType", userType) .signWith(SignatureAlgorithm.HS512, tokenSignKey) .compressWith(CompressionCodecs.GZIP) .compact(); return token; } //从token字符串获取userid public static Long getUserId(String token) { if(StringUtils.isEmpty(token)) return null; Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); Claims claims = claimsJws.getBody(); Integer userId = (Integer)claims.get("userId"); return userId.longValue(); } //从token字符串获取userType public static Integer getUserType(String token) { if(StringUtils.isEmpty(token)) return null; Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); Claims claims = claimsJws.getBody(); return (Integer)(claims.get("userType")); } //从token字符串获取userName public static String getUserName(String token) { if(StringUtils.isEmpty(token)) return ""; Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); Claims claims = claimsJws.getBody(); return (String)claims.get("userName"); } //判断token是否有效 public static boolean isExpiration(String token){ try { boolean isExpire = Jwts.parser() .setSigningKey(tokenSignKey) .parseClaimsJws(token) .getBody() .getExpiration().before(new Date()); //没有过期,有效,返回false return isExpire; }catch(Exception e) { //过期出现异常,返回true return true; } } /** * 刷新Token * @param token * @return */ public String refreshToken(String token) { String refreshedToken; try { final Claims claims = Jwts.parser() .setSigningKey(tokenSignKey) .parseClaimsJws(token) .getBody(); refreshedToken = JwtHelper.createToken(getUserId(token), getUserType(token)); } catch (Exception e) { refreshedToken = null; } return refreshedToken; } }
AuthContextHolder类
从request请求中获取token口令
public class AuthContextHolder { //从请求头token获取userid public static Long getUserIdToken(HttpServletRequest request) { //从请求头token String token = request.getHeader("token"); //调用工具类 Long userId = JwtHelper.getUserId(token); return userId; } //从请求头token获取name public static String getUserName(HttpServletRequest request) { //从header获取token String token = request.getHeader("token"); //jwt从token获取username String userName = JwtHelper.getUserName(token); return userName; } }
MD5加密类
public final class MD5 { public static String encrypt(String strSrc) { try { char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; //getBytes(String charsetName): 使用指定的字符集将字符串编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 byte[] bytes = strSrc.getBytes(); //获取MD5摘要算法的MessageDiges 的对象 MessageDigest md=MessageDigest.getInstance("MD5"); //使用了指定字节更新摘要 md.update(bytes); //对于给定数量的更新数据,digest 方法只能被调用一次。在调用 digest 之后,MessageDigest 对象被重新设置成其初始状态。 bytes = md.digest(); // 获取初识状态下摘要的长度 int j = bytes.length; char[] chars = new char[j * 2]; int k = 0; for (int i = 0; i < bytes.length; i++) { byte b = bytes[i]; chars[k++] = hexChars[b >>> 4 & 0xf]; chars[k++] = hexChars[b & 0xf]; } //返回加密后的md5密钥串 return new String(chars); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); throw new RuntimeException("MD5加密出错!!+" + e); } } }
全局统一返回类
@Data @ApiModel(value = "全局统一返回结果") public class Result<T> { @ApiModelProperty(value = "返回码") private Integer code; @ApiModelProperty(value = "返回消息") private String message; @ApiModelProperty(value = "返回数据") private T data; public Result(){} // 返回数据 protected static <T> Result<T> build(T data) { Result<T> result = new Result<T>(); if (data != null) result.setData(data); return result; } public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) { Result<T> result = build(body); result.setCode(resultCodeEnum.getCode()); result.setMessage(resultCodeEnum.getMessage()); return result; } public static<T> Result<T> ok(){ return Result.ok(null); } /** * 操作成功 * @param data * @param <T> * @return */ public static<T> Result<T> ok(T data){ Result<T> result = build(data); return build(data, ResultCodeEnum.SUCCESS); } public static<T> Result<T> fail(){ return Result.fail(null); } /** * 操作失败 * @param data * @param <T> * @return */ public static<T> Result<T> fail(T data){ Result<T> result = build(data); return build(data, ResultCodeEnum.FAIL); } public Result<T> message(String msg){ this.setMessage(msg); return this; } public Result<T> code(Integer code){ this.setCode(code); return this; } public boolean isOk() { if(this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) { return true; } return false; } }
返回状态结果响应类
@Getter public enum ResultCodeEnum { SUCCESS(200,"成功"), FAIL(201, "失败"), SERVICE_ERROR(2012, "服务异常"), ILLEGAL_REQUEST( 204, "非法请求"), PAY_RUN(205, "支付中"), ARGUMENT_VALID_ERROR(206, "参数校验错误"), LOGIN_ERROR(207, "用户名或密码错误"), LOGIN_AUTH(208, "未登陆"), PERMISSION(209, "没有权限"), SECKILL_NO_START(210, "秒杀还没开始"), SECKILL_RUN(211, "正在排队中"), SECKILL_NO_PAY_ORDER(212, "您有未支付的订单"), SECKILL_FINISH(213, "已售罄"), SECKILL_END(214, "秒杀已结束"), SECKILL_SUCCESS(215, "抢单成功"), SECKILL_FAIL(216, "抢单失败"), SECKILL_ILLEGAL(217, "请求不合法"), SECKILL_ORDER_SUCCESS(218, "下单成功"), COUPON_GET(220, "优惠券已经领取"), COUPON_LIMIT_GET(221, "优惠券已发放完毕"), //2022-02-22 LOGIN_CODE(222,"长时间未操作,会话已失效,请刷新页面后重试!"), CODE_ERROR(223,"验证码错误!"), TOKEN_ERROR(224,"Token无效!"); private Integer code; private String message; private ResultCodeEnum(Integer code, String message) { this.code = code; this.message = message; } }
文件上传类
public class UploadFile { //存储文件上传失败的错误信息 private static Map<String, Object> error_result = new HashMap<>(); //存储头像的上传结果信息 private static Map<String, Object> upload_result = new HashMap<>(); /** * @description: 效验所上传图片的大小及格式等信息... * @param: photo * @param: path * @return: java.util.Map<java.lang.String, java.lang.Object> */ private static Map<String, Object> uploadPhoto(MultipartFile photo, String path) { //限制头像大小(20M) int MAX_SIZE = 20971520; //获取图片的原始名称 String orginalName = photo.getOriginalFilename(); //如果保存文件的路径不存在,则创建该目录 File filePath = new File(path); if (!filePath.exists()) { filePath.mkdirs(); } //限制上传文件的大小 if (photo.getSize() > MAX_SIZE) { error_result.put("success", false); error_result.put("msg", "上传的图片大小不能超过20M哟!"); return error_result; } // 限制上传的文件类型 String[] suffixs = new String[]{".png", ".PNG", ".jpg", ".JPG", ".jpeg", ".JPEG", ".gif", ".GIF", ".bmp", ".BMP"}; SuffixFileFilter suffixFileFilter = new SuffixFileFilter(suffixs); if (!suffixFileFilter.accept(new File(path + orginalName))) { error_result.put("success", false); error_result.put("msg", "禁止上传此类型文件! 请上传图片哟!"); return error_result; } return null; } /** * @description: (提取公共代码 : 提高代码的可重用性)获取头像的上传结果信息 * @param: photo * @param: dirPaht * @param: portraitPath * @return: java.util.Map<java.lang.String, java.lang.Object> */ public static Map<String, Object> getUploadResult(MultipartFile photo, String dirPaht, String portraitPath) { if (!photo.isEmpty() && photo.getSize() > 0) { //获取图片的原始名称 String orginalName = photo.getOriginalFilename(); //上传图片,error_result:存储头像上传失败的错误信息 Map<String, Object> error_result = UploadFile.uploadPhoto(photo, dirPaht); if (error_result != null) { return error_result; } //使用UUID重命名图片名称(uuid__原始图片名称) String newPhotoName = UUID.randomUUID() + "__" + orginalName; //将上传的文件保存到目标目录下 try { photo.transferTo(new File(dirPaht + newPhotoName)); upload_result.put("success", true); upload_result.put("portrait_path", portraitPath + newPhotoName);//将存储头像的项目路径返回给页面 } catch (IOException e) { e.printStackTrace(); upload_result.put("success", false); upload_result.put("msg", "上传文件失败! 服务器端发生异常!"); return upload_result; } } else { upload_result.put("success", false); upload_result.put("msg", "头像上传失败! 未找到指定图片!"); } return upload_result; } }
pojo和mapper类
根据数据库表的信息,可以借助mybatis的逆向工程生成。
配至pom.xml
<!-- 依赖MyBatis核心包 --> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.7</version> </dependency> </dependencies> <!-- 控制Maven在构建过程中相关配置 --> <build> <!-- 构建过程中用到的插件 --> <plugins> <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 --> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.0</version> <!-- 插件的依赖 --> <dependencies> <!-- 逆向工程的核心依赖 --> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.2</version> </dependency> <!-- 数据库连接池 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.2</version> </dependency> <!-- MySQL驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.27</version> </dependency> </dependencies> </plugin> </plugins> </build>
配置generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <!-- targetRuntime: 执行生成的逆向工程的版本 MyBatis3Simple: 生成基本的CRUD(清新简洁版) MyBatis3: 生成带条件的CRUD(奢华尊享版) --> <context id="DB2Tables" targetRuntime="MyBatis3"> <!-- 数据库的连接信息 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://..../sc_tb" userId="root" password="123456"> </jdbcConnection> <!-- javaBean的生成策略--> <javaModelGenerator targetPackage="com.project.smart_campus.pojo" targetProject=".\src\main\java"> <property name="enableSubPackages" value="true" /> <property name="trimStrings" value="true" /> </javaModelGenerator> <!-- SQL映射文件的生成策略 --> <sqlMapGenerator targetPackage="com.project.smart_campus.mapper" targetProject=".\src\main\resources"> <property name="enableSubPackages" value="true" /> </sqlMapGenerator> <!-- Mapper接口的生成策略 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.project.smart_campus.mapper" targetProject=".\src\main\java"> <property name="enableSubPackages" value="true" /> </javaClientGenerator> <!-- 逆向分析的表 --> <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName --> <!-- domainObjectName属性指定生成出来的实体类的类名 --> <table tableName="tb_test" domainObjectName="Test"/> </context> </generatorConfiguration>
执行generate目标
生成相对应的mapper类和pojo类