> 文章列表 > 项目3:积分等级表接口的开发和使用(后台)

项目3:积分等级表接口的开发和使用(后台)

项目3:积分等级表接口的开发和使用(后台)

项目3:积分等级表接口的开发和使用

1.service-core的controller创建admin包

2.对积分登记表完成增删改查

3.配置swagger接口生成器和ui

4.统一设置返回结果

5.统一设置异常处理

6.统一日志处理

项目3:积分等级表接口的开发和使用

1.service-core的controller创建admin包

  • controlle包下的admin(后台管理系统)
  • controller包(前端管理网站系统)

2.对积分登记表完成增删改查

  • 后台管理系统
package com.atguigu.srb.core.controller.admin;import com.atguigu.common.exception.Assert;
import com.atguigu.common.result.R;
import com.atguigu.common.result.ResponseEnum;
import com.atguigu.srb.core.pojo.entity.IntegralGrade;
import com.atguigu.srb.core.service.IntegralGradeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import java.util.List;/* <p>* 积分等级表 前端控制器* </p> @author Likejin* @since 2023-04-09*/@Api(tags="积分等级管理")
@CrossOrigin
@RestController
@RequestMapping("/admin/core/integralGrade")
public class AdminIntegralGradeController {@Resourceprivate IntegralGradeService integralGradeService;@ApiOperation("积分等级列表")@GetMapping("/list")public R listAll(){List<IntegralGrade> list = integralGradeService.list();return R.ok().data("list",list).message("获取列表成功");}@ApiOperation("根据ID删除数据记录")@DeleteMapping("/remove/{id}")public R removeById(@ApiParam("数据id")@PathVariable Long id){boolean result = integralGradeService.removeById(id);if(result){return R.ok().message("删除成功");}return R.error().message("删除失败");}@ApiOperation("新增积分等级")@PostMapping("/save")public R save(@ApiParam(value = "积分等级对象",required = true)@RequestBody IntegralGrade integralGrade){//        if(integralGrade.getBorrowAmount()==null){
//            throw new BusinessException(ResponseEnum.BORROW_AMOUNT_NULL_ERROR);
//        }Assert.notNull(integralGrade.getBorrowAmount(), ResponseEnum.BORROW_AMOUNT_NULL_ERROR);boolean result = integralGradeService.save(integralGrade);if(result){return R.ok().message("保存成功");}return R.error().message("保存失败");}@ApiOperation("根据id获取积分等级")@GetMapping("/get/{id}")public R getById(@ApiParam(value = "数据id",required = true)@PathVariable Long id){IntegralGrade integralGrade = integralGradeService.getById(id);if(integralGrade != null){return R.ok().data("record",integralGrade);}return R.error().message("数据获取失败");}@ApiOperation("修改积分等级")@PutMapping("/update")public R updateById(@ApiParam(value = "积分等级对象",required = true)@RequestBody IntegralGrade integralGrade){boolean result = integralGradeService.updateById(integralGrade);if(result){return R.ok().message("更新成功");}return R.error().message("更新失败");}
}
  • 前端管理系统测试分组(swagger内的分组)
package com.atguigu.srb.core.controller;import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/* <p>* 积分等级表 前端控制器* </p> @author Likejin* @since 2023-04-09*/
@Api(tags = "网站积分接口")
@RestController
@RequestMapping("/api/core/integralGrade")
public class IntegralGradeController {@ApiOperation("测试接口")@GetMapping("/test")public void test(){return;}}

3.配置swagger接口生成器

①在service-base中创建config

  • 注意包名(能够让core的核心包扫描到)项目3:积分等级表接口的开发和使用(后台)
  • 具体代码(分组逻辑)
package com.atguigu.srb.base.config;import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration
@EnableSwagger2
public class Swagger2Config {//生成admin分组@Beanpublic Docket adminApiConfig() {return new Docket(DocumentationType.SWAGGER_2).groupName("adminApi")//增加分组//增加分组的描述.apiInfo(adminApiInfo()).select()//对路径为/admin的接口分到一组.paths(Predicates.and(PathSelectors.regex("/admin/.*"))).build();}private ApiInfo adminApiInfo(){return new ApiInfoBuilder().title("尚融宝后台管理系统API文档").description("本文档描述了尚融宝管理系统各个接口的调用方式").contact(new Contact("like","www.baidu.com","13030@qq.com")).build();}//生成web分组@Beanpublic Docket webApiConfig() {return new Docket(DocumentationType.SWAGGER_2).groupName("webApiInfo").apiInfo(adminApiInfo()).select().paths(Predicates.and(PathSelectors.regex("/api/.*"))).build();}private ApiInfo webApiInfo(){return new ApiInfoBuilder().title("尚融宝网站API文档").description("本文档描述了尚融宝网站各个接口的调用方式").contact(new Contact("like","www.baidu.com","13030@qq.com")).build();}}
  • 访问swagger的地址
    http://localhost:8110/swagger-ui.html

4.统一配置返回值(在guigu-common中)

①统一配置返回值

  • code:数字
  • message:字符串
  • data:对象

②设计思路

  • 设置封装返回结果的类R
  • 每次数字和字符串相匹配(封装为枚举类ResponseEnum)
  • 类R可以封装枚举类ResponseEnum,可以单独设置code,message,data
  • data类型可以为对象,可以为map

③代码

  • ResonseEnum枚举类
package com.atguigu.common.result;import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;@Getter
@AllArgsConstructor
@ToString
public enum ResponseEnum {SUCCESS(0, "成功"),ERROR(-1, "服务器内部错误"),//-1xx 服务器错误BAD_SQL_GRAMMAR_ERROR(-101, "sql语法错误"),SERVLET_ERROR(-102, "servlet请求异常"), //-2xx 参数校验UPLOAD_ERROR(-103, "文件上传错误"),EXPORT_DATA_ERROR(104, "数据导出失败"),//-2xx 参数校验BORROW_AMOUNT_NULL_ERROR(-201, "借款额度不能为空"),MOBILE_NULL_ERROR(-202, "手机号码不能为空"),MOBILE_ERROR(-203, "手机号码不正确"),PASSWORD_NULL_ERROR(204, "密码不能为空"),CODE_NULL_ERROR(205, "验证码不能为空"),CODE_ERROR(206, "验证码错误"),MOBILE_EXIST_ERROR(207, "手机号已被注册"),LOGIN_MOBILE_ERROR(208, "用户不存在"),LOGIN_PASSWORD_ERROR(209, "密码错误"),LOGIN_LOKED_ERROR(210, "用户被锁定"),LOGIN_AUTH_ERROR(-211, "未登录"),USER_BIND_IDCARD_EXIST_ERROR(-301, "身份证号码已绑定"),USER_NO_BIND_ERROR(302, "用户未绑定"),USER_NO_AMOUNT_ERROR(303, "用户信息未审核"),USER_AMOUNT_LESS_ERROR(304, "您的借款额度不足"),LEND_INVEST_ERROR(305, "当前状态无法投标"),LEND_FULL_SCALE_ERROR(306, "已满标,无法投标"),NOT_SUFFICIENT_FUNDS_ERROR(307, "余额不足,请充值"),PAY_UNIFIEDORDER_ERROR(401, "统一下单错误"),ALIYUN_SMS_LIMIT_CONTROL_ERROR(-502, "短信发送过于频繁"),//业务限流ALIYUN_SMS_ERROR(-503, "短信发送失败"),//其他失败WEIXIN_CALLBACK_PARAM_ERROR(-601, "回调参数不正确"),WEIXIN_FETCH_ACCESSTOKEN_ERROR(-602, "获取access_token失败"),WEIXIN_FETCH_USERINFO_ERROR(-603, "获取用户信息失败"),;// 响应状态码private Integer code;// 响应信息private String message;
}
  • R对象
package com.atguigu.common.result;import lombok.Data;import java.util.HashMap;
import java.util.Map;@Data
public class R {private Integer code;private String message;private Map<String, Object> data = new HashMap();//全都返回R对象方便连续赋值/* 构造器私有*/private R(){}/* 返回成功*/public static R ok(){R r = new R();r.setCode(ResponseEnum.SUCCESS.getCode());r.setMessage(ResponseEnum.SUCCESS.getMessage());return r;}/* 返回失败*/public static R error(){R r = new R();r.setCode(ResponseEnum.ERROR.getCode());r.setMessage(ResponseEnum.ERROR.getMessage());return r;}/* @param responseEnum:* @return R* @author Likejin* @description 设置特定的ResponseEnum* @date 2023/4/9 13:35*/public static R setResult(ResponseEnum responseEnum){R r = new R();r.setCode(responseEnum.getCode());r.setMessage(responseEnum.getMessage());return r;}/* @param message:* @return R* @author Likejin* @description 设置特定的message* @date 2023/4/9 13:42*/public R message(String message){this.setMessage(message);return this;}/* @param code:* @return R* @author Likejin* @description 设置特定的code* @date 2023/4/9 13:42*/public R code(Integer code){this.setCode(code);return this;}/* @param key:* @param value:* @return R* @author Likejin* @description 给R的data赋值(key,value)* @date 2023/4/9 13:37*/public R data(String key, Object value){this.data.put(key, value);return this;}/* @param map:* @return R* @author Likejin* @description 给R的data赋值(map)* @date 2023/4/9 13:46*/public R data(Map<String, Object> map){this.setData(map);return this;}
}

5.统一设置异常处理(在guigu-common中)

①思路

  • 分层异常
    controller前异常,可能是参数封装异常等
    controller后异常,可能是业务异常

  • 异常可能出现
    手动抛出异常
    JVM抛出异常

  • 解决方案
    设置自定义异常(code+message匹配返回结果的枚举类)+断言类用于解决手动抛出异常。

  • 异常处理
    让异常出现的位置都跳转到统一异常处理器,打印日志让后台管理员维护,返回R对象

②代码

  • 自定义异常
package com.atguigu.common.exception;import com.atguigu.common.result.ResponseEnum;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
public class BusinessException extends RuntimeException {//状态码private Integer code;//错误消息private String message;/ @param message 错误消息*/public BusinessException(String message) {this.message = message;}/ @param message 错误消息* @param code 错误码*/public BusinessException(String message, Integer code) {this.message = message;this.code = code;}/ @param message 错误消息* @param code 错误码* @param cause 原始异常对象*/public BusinessException(String message, Integer code, Throwable cause) {super(cause);this.message = message;this.code = code;}/ @param resultCodeEnum 接收枚举类型*/public BusinessException(ResponseEnum resultCodeEnum) {this.message = resultCodeEnum.getMessage();this.code = resultCodeEnum.getCode();}/ @param resultCodeEnum 接收枚举类型* @param cause 原始异常对象*/public BusinessException(ResponseEnum resultCodeEnum, Throwable cause) {super(cause);this.message = resultCodeEnum.getMessage();this.code = resultCodeEnum.getCode();}}
  • 断言
package com.atguigu.common.exception;import com.atguigu.common.result.ResponseEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;@Slf4j
public abstract class Assert {/* 断言对象不为空* 如果对象obj为空,则抛出异常* @param obj 待判断对象*/public static void notNull(Object obj, ResponseEnum responseEnum) {if (obj == null) {log.info("obj is null...............");throw new BusinessException(responseEnum);}}/* 断言对象为空* 如果对象obj不为空,则抛出异常* @param object* @param responseEnum*/public static void isNull(Object object, ResponseEnum responseEnum) {if (object != null) {log.info("obj is not null......");throw new BusinessException(responseEnum);}}/* 断言表达式为真* 如果不为真,则抛出异常 @param expression 是否成功*/public static void isTrue(boolean expression, ResponseEnum responseEnum) {if (!expression) {log.info("fail...............");throw new BusinessException(responseEnum);}}/* 断言两个对象不相等* 如果相等,则抛出异常* @param m1* @param m2* @param responseEnum*/public static void notEquals(Object m1, Object m2,  ResponseEnum responseEnum) {if (m1.equals(m2)) {log.info("equals...............");throw new BusinessException(responseEnum);}}/* 断言两个对象相等* 如果不相等,则抛出异常* @param m1* @param m2* @param responseEnum*/public static void equals(Object m1, Object m2,  ResponseEnum responseEnum) {if (!m1.equals(m2)) {log.info("not equals...............");throw new BusinessException(responseEnum);}}/* 断言参数不为空* 如果为空,则抛出异常* @param s* @param responseEnum*/public static void notEmpty(String s, ResponseEnum responseEnum) {if (StringUtils.isEmpty(s)) {log.info("is empty...............");throw new BusinessException(responseEnum);}}
}

具体controller中的断言+自定义异常

Assert.notNull(integralGrade.getBorrowAmount(), ResponseEnum.BORROW_AMOUNT_NULL_ERROR);
  • 统一异常处理
package com.atguigu.common.exception;import com.atguigu.common.result.R;
import com.atguigu.common.result.ResponseEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;//执行方法的异常切面,所有方法自动调用,自动捕获所有异常
@Slf4j
@RestControllerAdvice
public class UnifielExceptionhandler {//不灵活@ExceptionHandler(value = Exception.class)public R handleException(Exception e){log.error(e.getMessage());return  R.error();}//定义特定的异常处理方式,繁琐@ExceptionHandler(BadSqlGrammarException.class)public R handleException(BadSqlGrammarException e){log.error(e.getMessage(),e);return  R.setResult(ResponseEnum.BAD_SQL_GRAMMAR_ERROR);}/* @param e:* @return R* @author Likejin* @description 自定义处理异常(利用状态码)* @date 2023/4/9 14:41*///返回R对象 code和message@ExceptionHandler(BusinessException.class)public R handleException(BusinessException e){log.error(e.getMessage(),e);return  R.error().message(e.getMessage()).code(e.getCode());}/* Controller上一层相关异常,HTTP请求参数封装异常等*/@ExceptionHandler({NoHandlerFoundException.class,HttpRequestMethodNotSupportedException.class,HttpMediaTypeNotSupportedException.class,MissingPathVariableException.class,MissingServletRequestParameterException.class,TypeMismatchException.class,HttpMessageNotReadableException.class,HttpMessageNotWritableException.class,MethodArgumentNotValidException.class,HttpMediaTypeNotAcceptableException.class,ServletRequestBindingException.class,ConversionNotSupportedException.class,MissingServletRequestPartException.class,AsyncRequestTimeoutException.class})public R handleServletException(Exception e) {log.error(e.getMessage(), e);//SERVLET_ERROR(-102, "servlet请求异常"),return R.error().message(ResponseEnum.SERVLET_ERROR.getMessage()).code(ResponseEnum.SERVLET_ERROR.getCode());}
}

③执行流程

  • 前端传入参数
    直接发送参数封装异常,异常处理器捕获,直接返回-102, servlet请求异常状态码。
  • controller内自定义异常(某参数不能为空)
    根据断言抛出自定义异常(封装状态码),自定义异常被异常处理器捕获,根据状态码返回R对象。

6.统一日志处理

①统一日志处理

  • 什么时候日志输出
  • 输出的格式是什么
  • 日志输出到控制台还是文档

②日志基本知识

  • 日志级别
    TRACE 大量日志
    DEBUG 少量日志
    INFO 默认日志级别
    WARN 警告
    ERROR 错误日志
    设置了INFO其上的WARN和ERROR日志都会打印
  • 环境日志
    生成环境需要生成文档
    测试环境和开发环境不需要生成文档
  • 滚动日志
    日志文件过大,日志的读写消耗系统内存
    可以设置策略:一天分开一次日志,并且每天的日志超过一定空间还会再分

③设置统一日志输出思路

  • logback是spring提供的日志管理
  • 简易日志级别(在application.yml中)
# 设置日志级别
logging:level:root: ERROR
  • 日志管理器管理(删除application.yml配置的级别,配置logback-spring.xml)
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--标志位,区分不同的应用程序--><contextName>atguiguSrb</contextName><!-- 日志的输出目录 --><property name="log.path" value="F:/Project_shangrongbao/java/srb/srb-log" /><!--控制台日志格式:彩色日志--><!-- magenta:洋红 --><!-- boldMagenta:粗红--><!-- cyan:青色 --><!-- white:白色 --><!-- magenta:洋红 --><property name="CONSOLE_LOG_PATTERN"value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) %highlight([%-5level]) %green(%logger) %msg%n"/><!--文件日志格式--><property name="FILE_LOG_PATTERN"value="%date{yyyy-MM-dd HH:mm:ss} [%-5level] %thread %file:%line %logger %msg%n" /><!--编码--><property name="ENCODING"value="UTF-8" /><!-- 控制台日志 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>${CONSOLE_LOG_PATTERN}</pattern><charset>${ENCODING}</charset></encoder></appender><!-- 文件日志 --><appender name="FILE" class="ch.qos.logback.core.FileAppender"><file>${log.path}/log.log</file><append>true</append><encoder><pattern>${FILE_LOG_PATTERN}</pattern><charset>${ENCODING}</charset></encoder></appender><!--名称即为包名了,其包下面的文件都会被日志记录器管理--><!--file和console都打印--><!--环境配置了此不用配置--><!-- 日志记录器  --><!--<logger name="com.atguigu" level="INFO">--><!--<appender-ref ref="CONSOLE" />--><!--<appender-ref ref="FILE" />--><!--</logger>--><!--设置滚动日志,时间的滚动策略--><appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><!--  要区别于其他的appender中的文件名字  --><file>${log.path}/log-rolling.log</file><encoder><pattern>${FILE_LOG_PATTERN}</pattern><charset>${ENCODING}</charset></encoder><!-- 设置滚动日志记录的滚动策略 --><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 日志归档路径以及格式 --><fileNamePattern>${log.path}/info/log-rolling-%d{yyyy-MM-dd}.%i.log</fileNamePattern><!--归档日志文件保留的最大数量--><maxHistory>15</maxHistory><!--包含上size,防止一天的日志文件过大,超过下面的大小,再分--><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>1kb</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy></appender><!--多环境配置--><!-- 开发环境和测试环境 --><!--name和application.yml配合使用--><springProfile name="dev,test"><logger name="com.atguigu" level="INFO"><appender-ref ref="CONSOLE" /><appender-ref ref="ROLLING_FILE" /></logger></springProfile><!-- 生产环境 --><springProfile name="prod"><logger name="com.atguigu" level="ERROR"><appender-ref ref="CONSOLE" /><appender-ref ref="ROLLING_FILE" /></logger></springProfile></configuration>
  • 与application.yml中环境的配置配合使用
spring:profiles:active: dev # 环境设置
  • 结果
    实时日志
    项目3:积分等级表接口的开发和使用(后台)
    日志归档
    项目3:积分等级表接口的开发和使用(后台)

未更新

未更新

未更新

未更新

未更新

未更新

未更新

未更新