项目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;

/**
 * 

* 积分等级表 前端控制器 *

* * @author Likejin * @since 2023-04-09 */
@Api(tags="积分等级管理") @CrossOrigin @RestController @RequestMapping("/admin/core/integralGrade") public class AdminIntegralGradeController { @Resource private 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;

/**
 * 

* 积分等级表 前端控制器 *

* * @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:积分等级表接口的开发和使用(后台)_第1张图片
  • 具体代码(分组逻辑)
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分组
    @Bean
    public 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","[email protected]"))
                .build();

    }

    //生成web分组
    @Bean
    public 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","[email protected]"))
                .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)

<configuration>
    
    <contextName>atguiguSrbcontextName>

    
    <property name="log.path" value="F:/Project_shangrongbao/java/srb/srb-log" />

    
    
    
    
    
    
    <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.logfile>
        <append>trueappend>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}pattern>
            <charset>${ENCODING}charset>
        encoder>
    appender>

    
    
    
    
    
        
        
    


    
    <appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">

        
        <file>${log.path}/log-rolling.logfile>
        <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.logfileNamePattern>
            
            <maxHistory>15maxHistory>
            
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>1kbmaxFileSize>
            timeBasedFileNamingAndTriggeringPolicy>
        rollingPolicy>

    appender>

    
    
    
    <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:积分等级表接口的开发和使用(后台)_第2张图片

未更新

未更新

未更新

未更新

未更新

未更新

未更新

未更新

你可能感兴趣的:(项目1:金融借钱还钱,java,前端,spring)