项目学习总结(一)

  • 前端部分,使用主流的前端框架Vue,使用Es6的开发规范,采用模块化的开发模式。
  • 后端部分,使用目前流行的SpringBoot+SpringCloud进行微服务架构,使用Feign、Gateway、Hystrix,以及阿里巴巴的Nacos等组件搭建了项目的基础环境

总结一下学习到的(复习的)知识:
创建项目,依赖管理,mybatis plus使用(主键生成,自动填充…),Swagger,统一返回结果对象,分页功能,条件查询,统一异常处理,统一日志…

创建项目:

最外层父项目:

packaging为pom形式

在artifactId后面设置

在父项目中可以设置<properties><dependencyManagement>控制(依赖)版本问题

中间层项目(子模块):

packaging同样为pom形式,只需要引入依赖(不需要标注版本 -> 版本在最外层已定义)

配置application.properties

# 服务端口
server.port=8001
# 服务名
spring.application.name=service-edu

# 环境设置:dev、test、prod
spring.profiles.active=dev

# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

## 设置日志级别
#logging.level.root=WARN
##mybatis日志
#mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl


项目中使用MP(Mybatis Plus)

  1. 设计数据库表(要有id, gmt_create, gmt_modified)
  2. 在test文件夹中创建自定义generator类,例如:
    /**
     * FileName: demo
     * Author: Haozhancc
     * Date: 2022/4/20 9:43
     */
    public class CodeGenerator {
    
        @Test
        public void run() {
    
            // 1、创建代码生成器
            AutoGenerator mpg = new AutoGenerator();
    
            // 2、全局配置
            GlobalConfig gc = new GlobalConfig();
            String projectPath = System.getProperty("user.dir");
            //最好用绝对路径
            gc.setOutputDir("C:\\Users\\52637\\Desktop\\项目\\guli_parent\\service\\service_edu" + "/src/main/java");
    
            gc.setAuthor("haozhancc");
            gc.setOpen(false); //生成后是否打开资源管理器
            gc.setFileOverride(false); //重新生成时文件是否覆盖
    
            gc.setServiceName("%sService");	//去掉Service接口的首字母I
            //这一步根据主键的形式设置,如果是int类型就ID_WORKER,String就ID_WORKER_STR
            gc.setIdType(IdType.ID_WORKER_STR); //主键策略
            gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
            gc.setSwagger2(true);//开启Swagger2模式
    
            mpg.setGlobalConfig(gc);
    
            // 3、数据源配置
            DataSourceConfig dsc = new DataSourceConfig();
            dsc.setUrl("jdbc:mysql://localhost:3306/guli?serverTimezone=GMT%2B8");
            dsc.setDriverName("com.mysql.cj.jdbc.Driver");
            dsc.setUsername("root");
            dsc.setPassword("123456");
            dsc.setDbType(DbType.MYSQL);
            mpg.setDataSource(dsc);
    
            // 4、包配置
            PackageConfig pc = new PackageConfig();
            pc.setParent("com.haozhancc");
            pc.setModuleName("eduservice"); //模块名
    
            pc.setController("controller");
            pc.setEntity("entity");
            pc.setService("service");
            pc.setMapper("mapper");
            mpg.setPackageInfo(pc);
    
            // 5、策略配置
            StrategyConfig strategy = new StrategyConfig();
            strategy.setInclude("edu_teacher");
            strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
            strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
    
            strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
            strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
    
            strategy.setRestControllerStyle(true); //restful api风格控制器
            strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
    
            mpg.setStrategy(strategy);
    
    
            // 6、执行
            mpg.execute();
        }
    }	
    

    Mybatis Plus主键生成策略

    1. 主键增长
    2. UUID
    3. redis
    4. mp默认的snowflake算法

自动填充

  1. 在private Date gmt_created上添加@TableField(fill = FieldFill.INSERT)注解
  2. 配合自己写一个Handler(别忘了扫描组件)
    /**
     * FileName: MyMetaObjectHandler
     * Author: Haozhancc
     * Date: 2022/4/20 14:25
     */
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
        @Override
        public void insertFill(MetaObject metaObject) {
            //属性名称,不是字段名称
            this.setFieldValByName("gmtCreate", new Date(), metaObject);
            this.setFieldValByName("gmtModified", new Date(), metaObject);
        }
    
        @Override
        public void updateFill(MetaObject metaObject) {
            this.setFieldValByName("gmtModified", new Date(), metaObject);
        }
    }
    

删除功能

逻辑删除需要配置插件(数据库也要有对应字段) [注入bean]
配合注解==@TableLogic==

如果路径传入值例如:
@DeleteMapping(“{id}”)
需要在方法上对应使用@PathVariable来获取

接口测试工具 (Swagger)

swagger是一个规范和完整的框架,用于生成,描述,调用和可视化RESTful风格的web服务.

项目中如何整合Swagger

创建公共模块 整合 Swagger(所有模块均可以使用)

  1. 引入依赖
    <!--swagger-->
    <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger2</artifactId>
       <scope>provided</scope>
    </dependency>
    
    <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger-ui</artifactId>
       <scope>provided</scope>
    </dependency>
    
  2. 在公共模块中编写SwaggerConfig配置Swagger
    /**
     * FileName: SwaggerConfig
     * Author: Haozhancc
     * Date: 2022/4/20 10:27
     */
    
    @Configuration  //配置类
    @EnableSwagger2 //swagger注解
    public class SwaggerConfig {
        @Bean
        public Docket webApiConfig(){
            return new Docket(DocumentationType.SWAGGER_2)
                    .groupName("webApi")
                    .apiInfo(webApiInfo())
                    .select()
                    .paths(Predicates.not(PathSelectors.regex("/admin/.*")))
                    .paths(Predicates.not(PathSelectors.regex("/error.*")))
                    .build();
        }
    
        private ApiInfo webApiInfo(){
            return new ApiInfoBuilder()
                    .title("标题")
                    .description("描述")
                    .version("1.0")
                    .contact(new Contact("Helen", "http://xxx.com", "XXXXXXXX@qq.com"))
                    .build();
        }
    }
    
  3. 在其他需要Swagger的地方引入公共模块依赖
  4. 在启动类上加入@ComponentScan(basePackaged = {com.xxx})注解扫描这个配置类

结束! 访问http://localhost:8001/swagger-ui.html

统一返回值

同样放到通用包

/**
 * 统一返回结果
 * FileName: R
 * Author: Haozhancc
 * Date: 2022/4/20 10:55
 */
@Data
public class R {
    @ApiModelProperty(value = "是否成功")
    private Boolean success;
    @ApiModelProperty(value = "返回码")
    private Integer code;
    @ApiModelProperty(value = "返回消息")
    private String message;
    @ApiModelProperty(value = "返回数据")
    private Map<String, Object> data = new HashMap<String, Object>();

    //私有构造方法
    private R() {}

    //成功静态方法
    public static R ok() {
        R r = new R();
        r.setSuccess(true);
        r.setCode(ResultCode.SUCCESS);
        r.setMessage("成功");
        return r;
    }

    //失败静态方法
    public static R error() {
        R r = new R();
        r.setSuccess(false);
        r.setCode(ResultCode.ERROR);
        r.setMessage("失败");
        return r;
    }

    public R success(Boolean success){
        this.setSuccess(success);
        return this;
    }

    public R message(String message){
        this.setMessage(message);
        return this;
    }

    public R code(Integer code){
        this.setCode(code);
        return this;
    }

    public R data(String key, Object value){
        this.data.put(key, value);
        return this;
    }

    public R data(Map<String, Object> map){
        this.setData(map);
        return this;
    }
}

配合

/**
 * FileName: ResultCode
 * Author: Haozhancc
 * Date: 2022/4/20 10:51
 */
public interface ResultCode {
    public static Integer SUCCESS = 20000;  //成功
    public static Integer ERROR = 20001;    //失败
}

接口可以换成枚举类…
调用时 例如return R.ok().data("xxx",list);

分页功能

配置插件:

@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}

具体代码编写:

//3.分页查询讲师方法
@GetMapping("pageTeacher/{current}/{limit}")
public R pageListTeacher(@PathVariable long current,
                         @PathVariable long limit) {

    //创建page对象
    Page<EduTeacher> pageTeacher = new Page<>(current, limit);
    //调用方法实现分页
    //调用方法的时候,底层封装,把分页所有数据封装到pageTeacher对象里面
    teacherService.page(pageTeacher, null);

    long total = pageTeacher.getTotal();    //总记录数
    List<EduTeacher> records = pageTeacher.getRecords();
    return R.ok().data("total", total).data("rows", records);
}

条件查询(分页)

在wrapper中传的是表中的字段 而 自动填充传的是类的属性

//4.条件查询待分页的方法
    @PostMapping("pageTeacherCondition/{current}/{limit}")
    public R pageTeacherCondition(@PathVariable long current,
                                  @PathVariable long limit,
                                  @RequestBody(required = false) TeacherQuery teacherQuery) {
        //创建page对象
        Page<EduTeacher> pageTeacher = new Page<>(current, limit);
        //构建条件
        QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
        // 多条件组合查询 wrapper.
        // 动态SQL
        String name = teacherQuery.getName();
        Integer level = teacherQuery.getLevel();
        String begin = teacherQuery.getBegin();
        String end = teacherQuery.getEnd();
        if (!StringUtils.isNullOrEmpty(name)) {
            //构建条件
            wrapper.like("name", name);
        }
        if (null != level) {
            wrapper.eq("level", level);
        }
        if (!StringUtils.isNullOrEmpty(begin)) {
            wrapper.ge("gmt_create", begin);
        }
        if (!StringUtils.isNullOrEmpty(end)) {
            wrapper.le("gmt_create", end);
        }

        wrapper.orderByDesc("gmt_create");

        //调用方法实现条件查询分页
        teacherService.page(pageTeacher, wrapper);
        long total = pageTeacher.getTotal();
        List<EduTeacher> records = pageTeacher.getRecords();    //数据list集合
        return R.ok().data("total", total).data("rows",records);
    }

使用@RequestBody不能使用@GetMapping,只能使用@PostMapping
如果可以没有:@RequestBody(required = false)
@ResponseBody是返回json数据, @RequestBody是接收json数据

统一异常处理

/**
 * FileName: GlobalExceptionHandler
 * Author: Haozhancc
 * Date: 2022/4/20 15:06
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    //全局异常
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public R error(Exception e) {
        e.printStackTrace();
        return R.error().message("执行了全局异常处理");
    }

    //特定异常
    @ExceptionHandler(ArithmeticException.class)
    @ResponseBody
    public R error(ArithmeticException e) {
        e.printStackTrace();
        return R.error().message("执行了ArithmeticException异常处理");
    }

    //自定义异常
    @ExceptionHandler(GuliException.class)
    @ResponseBody
    public R error(GuliException e) {
        e.printStackTrace();
        return R.error().code(e.getCode()).message(e.getMsg());
    }
}

自定义异常 继承 RuntimeException:

/**
 * FileName: GuliException
 * Author: Haozhancc
 * Date: 2022/4/20 15:26
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class GuliException extends RuntimeException{

    private Integer code;
    private String msg;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值