• 前后端分离开发


    前后端分离开发

    前后端分离开发后,从工程结构上也会发生变化,即前后端代码不在混合在一个maven工程中,而是分为前端工程和后端工程

    后端工程会部署到Tomcat中

    前端工程会部署到Nginx中

    YApi

    源码地址:https://github.com/YMFE/yapi

    要使用YApi,需要自己进行部署

    Swagger

    使用Swagger你只需要按照它的规范取定义接口及接口相关的信息,在通过Swagger衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,以及在线调试页面等功能。

    knife4j是为Java MVC框架集成Swagger生成的Api文档的增强解决方案

    依赖坐标

    
        com.github.xiaoymin
        knife4j-spring-boot-starter
        3.0.2
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    修改WebMvcConfig

    package com.itheima.reggie.config;
    
    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.module.SimpleModule;
    import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
    import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
    import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
    import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
    import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
    import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
    import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
    import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
    import com.itheima.reggie.common.JacksonObjectMapper;
    import com.itheima.reggie.entity.Employee;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    import java.math.BigInteger;
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    import java.time.LocalTime;
    import java.time.format.DateTimeFormatter;
    import java.util.List;
    
    import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
    
    @Slf4j
    @Configuration
    @EnableSwagger2
    @EnableKnife4j
    public class WebMvcConfig extends WebMvcConfigurationSupport {
    
        /**
         * 设置静态资源映射
         * @param registry
         */
        @Override
        protected void addResourceHandlers(ResourceHandlerRegistry registry) {
            log.info("开始进行静态资源映射...");
            registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
            registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
            registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
            registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
        }
    
        /**
         * 扩展mvc框架的消息转换器
         * @param converters
         */
        @Override
        protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
            log.info("扩展消息转换器...");
            //创建消息转换器对象
            MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
            //设置对象转换器,底层使用Jackson将Java对象转为json
            messageConverter.setObjectMapper(new JacksonObjectMapper());
            //将上面的消息转换器对象追加到mvc框架的转换器集合中
            converters.add(0,messageConverter);
        }
    
        @Bean
        public Docket createRestApi() {
            // 文档类型
            return new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo())
                    .select()
                    .apis(RequestHandlerSelectors.basePackage("com.itheima.reggie.controller"))
                    .paths(PathSelectors.any())
                    .build();
        }
    
        private ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                    .title("瑞吉外卖")
                    .version("1.0")
                    .description("瑞吉外卖接口文档")
                    .build();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    在过滤器中配置不需要拦截的路径

    "/doc.html",
    "/webjars/**",
    "/swagger-resources",
    "/v2/api-docs"
    
    • 1
    • 2
    • 3
    • 4

    直接访问即可http://localhost:8080/doc.html

    注解说明
    @Api用在请求的类上,例如@Controller,表示对类的说明
    @ApiModel用在类上,通常是实体类,表示一个返回响应数据的信息
    @ApiModelProperty用在属性上,描述响应类的属性
    @ApiOperation用在请求的方法上,说明方法的用途,作用
    @ApiImplicitParams用在请求的方法上,表示一组参数的说明
    @ApiImplicitParam用在注解中,指定一个请求参数的各个方面

    注解演示@ApiModel和@ApiModelProperty

    package com.itheima.reggie.entity;
    
    import com.baomidou.mybatisplus.annotation.FieldFill;
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.Data;
    import java.io.Serializable;
    import java.math.BigDecimal;
    import java.time.LocalDateTime;
    
    /**
     * 套餐
     */
    @ApiModel("套餐")
    @Data
    public class Setmeal implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @ApiModelProperty("id主键")
        private Long id;
    
    @ApiModelProperty("分类id")
        //分类id
        private Long categoryId;
    
        @ApiModelProperty("套餐名称")
        //套餐名称
        private String name;
    
        @ApiModelProperty("套餐价格")
        //套餐价格
        private BigDecimal price;
    
        @ApiModelProperty("状态 0:停用 1:启用")
        //状态 0:停用 1:启用
        private Integer status;
    
        @ApiModelProperty("编码")
        //编码
        private String code;
    
        @ApiModelProperty("描述信息")
        //描述信息
        private String description;
    
        @ApiModelProperty("图片")
        //图片
        private String image;
    
    
        @TableField(fill = FieldFill.INSERT)
        private LocalDateTime createTime;
    
    
        @TableField(fill = FieldFill.INSERT_UPDATE)
        private LocalDateTime updateTime;
    
    
        @TableField(fill = FieldFill.INSERT)
        private Long createUser;
    
    
        @TableField(fill = FieldFill.INSERT_UPDATE)
        private Long updateUser;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    注解演示:@Api

    @RestController
    @RequestMapping("/setmeal")
    @Slf4j
    @Api(tags = "套餐相关接口")
    public class SetmealController {...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注解演示:@ApiOperation

    /**
     * 新增套餐
     * @param setmealDto
     * @return
     */
    @ApiOperation(value = "新增套餐接口")
    @CacheEvict(value = "setmealCache",allEntries = true)
    @PostMapping
    public R save(@RequestBody SetmealDto setmealDto){
        log.info("套餐信息:{}",setmealDto);
    
        setmealService.saveWithDish(setmealDto);
    
        return R.success("新增套餐成功");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注解演示@ApiImplicitParams和@@ApiImplicitParam

    /**
     * 套餐分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page",value = "页码",required = true),
            @ApiImplicitParam(name = "pageSize",value = "每页记录数",required = true),
            @ApiImplicitParam(name = "name",value = "套餐名称",required = false)
    })
    public R page(int page,int pageSize,String name){
        //分页构造器对象
        Page pageInfo = new Page<>(page,pageSize);
        Page dtoPage = new Page<>();
    
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
        //添加查询条件,根据name进行like模糊查询
        queryWrapper.like(name != null,Setmeal::getName,name);
        //添加排序条件,根据更新时间降序排列
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);
    
        setmealService.page(pageInfo,queryWrapper);
    
        //对象拷贝
        BeanUtils.copyProperties(pageInfo,dtoPage,"records");
        List records = pageInfo.getRecords();
    
        List list = records.stream().map((item) -> {
            SetmealDto setmealDto = new SetmealDto();
            //对象拷贝
            BeanUtils.copyProperties(item,setmealDto);
            //分类id
            Long categoryId = item.getCategoryId();
            //根据分类id查询分类对象
            Category category = categoryService.getById(categoryId);
            if(category != null){
                //分类名称
                String categoryName = category.getName();
                setmealDto.setCategoryName(categoryName);
            }
            return setmealDto;
        }).collect(Collectors.toList());
    
        dtoPage.setRecords(list);
        return R.success(dtoPage);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
  • 相关阅读:
    Cesium之Web Workers
    【华为OD题库-033】经典屏保-java
    跟羽夏学 Ghidra ——初识
    军用FPGA软件 Verilog语言的编码准测之触发器、锁存器
    前端三剑客——CSS
    Flutter SliverAppBar 吸顶效果
    ip netns网络空间使用
    hive和hadoop版本对应关系
    【优化求解】基于遗传算法优化PARSEC 方法的翼型形状附matlab代码
    如何制作企业招聘二维码?
  • 原文地址:https://blog.csdn.net/qq_57907966/article/details/126297421