外卖项目总结

项目经验

用过滤器判断用户是否登录,然后将用户id 用threadlocal类的set 方法 放在线程副本中,然后在要用到的时候取出来,然后我把set方法写在doFilter后面, 后面要取的时候这么取不出来,不知道是取不到还是set进去,

然后发现整个线程先走dofilter,要将set方法写到doFilter前面才能设置进去,要不然后面get不到,

doFilter

一.chain.doFilter作用
1.一般filter都是一个链,web.xml 里面配置了几个就有几个。一个一个的连在一起
request -> filter1 -> filter2 ->filter3 -> …. -> request resource.

2.chain.doFilter将请求转发给过滤器链下一个filter , 如果没有filter那就是你请求的资源

@Order(1) 确定顺序

@WebFilter(filterName = "first" , urlPatterns = "/*")
@Order(1)
public class FirstFilter implements Filter {

在进行修改的时候要先进行回显, 由于id是long类型且用雪花算法生成的19位的数字,long类型在js中只能回显17,不够的用0补,然后前后端数据就不一样了,修改好的数据传给后端update就失败了,这时就要用对象映射器,继承jackson包的objectMapper类,并在webMvcConfig类进行注册消息转换器

小bug给用户端的菜品展示没有没有口味,所以要构造一个dishDto类,将口味类加进去

在前端

用户权限管理

一个管理员用户,前端<el-button 组件 > 会判断用户id是否为1,来确定是否是管理员,确定是否展示禁用,启用按钮

image-20220621164631946

静态资源映射

1.继承WebMvcConfigurationSupport

2.添加@Configuration注解

@Slf4j
@Configuration
@EnableSwagger2
@EnableKnife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {
     /**
     * 静态资源映射
     * ("classpath:/backend/");    其中的/ 代表的是target
     * @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/");
    }
}

返回结果类

导入返回结果类,就是通用的结果类,将结果封装到结果中

package com.itheima.reggie.common;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
@Data
@ApiModel(value = "返回统一对象")
public class R<T> implements Serializable {
    @ApiModelProperty(value = "编码")
    private Integer code; //编码:1成功,0和其它数字为失败
    @ApiModelProperty(value = "错误信息")
    private String msg; //错误信息
    @ApiModelProperty(value = "数据")
    private T data; //数据
    @ApiModelProperty(value = "数据")
    private Map map = new HashMap(); //动态数据
    public static <T> R<T> success(T object) {
        R<T> r = new R<T>();
        r.data = object;
        r.code = 1;
        return r;
    }
    public static <T> R<T> error(String msg) {
        R r = new R();
        r.msg = msg;
        r.code = 0;
        return r;
    }
    public R<T> add(String key, Object value) {
        this.map.put(key, value);
        return this;
    }
}

用户登录

image-20220621155016701

用户登出

删除 用户session

完善用户登录功能

image-20220621155612269

image-20220621155651110

在过滤器类上加@WebFilter(filterName = “LoginCheckFilter”, urlPatterns = “/*”)注解

启动类增加 @ServletComponentScan

package com.itheima.reggie;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Slf4j
@SpringBootApplication
@ServletComponentScan
@EnableCaching
public class ReggieApplication {
    public static void main(String[] args) {
        SpringApplication.run(ReggieApplication.class,args);
        log.info("项目启动成功......");
    }
}

package com.itheima.reggie.filter;

import com.alibaba.fastjson.JSON;
import com.itheima.reggie.common.BaseContext;
import com.itheima.reggie.common.R;
import com.itheima.reggie.entity.Employee;
import com.itheima.reggie.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(filterName = "LoginCheckFilter", urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {
    private final static AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;

        log.info("过滤器拦截到的请求: {}", httpServletRequest.getRequestURI());

        //不需要拦截的路径
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**",
                "/user/login",
                "/user/sendMsg",
                "/doc.html",
                "/webjars/**",
                "/swagger-resources",
                "/v2/api-docs"
        };
        boolean check = check(urls, httpServletRequest.getRequestURI());
        if (check) {
            log.info("放行的请求:{}", httpServletRequest.getRequestURI());
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        //后端用户登录状态
        Employee employee = (Employee) httpServletRequest.getSession().getAttribute("employee");
        Long empId = employee.getId();
        if (employee != null) {
            // BaseContext.setCurrentId(empId);方法一定要写在  filterChain.doFilter(servletRequest, servletResponse);
            BaseContext.setCurrentId(empId);
            filterChain.doFilter(servletRequest, servletResponse);
            //  BaseContext.setCurrentId(empId);
            log.info("得到的用户id为 {} " + empId);
            return;
        }

        //前端用户登录状态
        User user = (User) httpServletRequest.getSession().getAttribute("user");
        Long userId = employee.getId();
        if (user != null) {
            // BaseContext.setCurrentId(empId);方法一定要写在  filterChain.doFilter(servletRequest, servletResponse);
            BaseContext.setCurrentId(userId);
            filterChain.doFilter(servletRequest, servletResponse);
            //  BaseContext.setCurrentId(empId);
            return;
        }
        log.info("没有用户登录");
        httpServletResponse.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
        return;
    }

    private boolean check(String[] urls, String requestUrl) {
        for (String url : urls) {
            boolean match = PATH_MATCHER.match(url, requestUrl);
            if (match) {
                return true;
            }
        }
        return false;
    }
}

全局异常处理

在添加时添加的名称是一样

@ControllerAdvice(annotations = {RestController.class, Controller.class}) 通知拦截那些controller

@ResponseBody 以json数据返回

@ExceptionHandler(SQLIntegrityConstraintViolationException.class) 捕获异常

package com.itheima.reggie.common;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.sql.SQLIntegrityConstraintViolationException;

/**
 * 全局异常处理器
 */
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 不重复字段  重复异常
     * @param ex
     * @return
     */
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){
        String message = ex.getMessage();

        if (message.contains("Duplicate entry")){
            String[] split = message.split(" ");
            String s = split[2]+"已经存在";
            log.error(s);
            return R.error(s);
        }
      return R.error("未知错误");
    }

    /**
     * 自定义异常类抛出
     * @param ex
     * @return
     */
    @ExceptionHandler(CustomException.class)
    public R<String> customException(CustomException ex){
        String message = ex.getMessage();
        log.error(message);
        return R.error(message);
    }
}

分页

package com.itheima.reggie.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * mybatisPlus进行分页 注册
 */
@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}
  /**
     * 分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public R<Page> page(long page ,long pageSize ,String name){
        log.info("分页请求数据   page={}   pageSize={}  name={}",page,pageSize,name);
        Page pageInfo = new Page(page,pageSize);
        
        
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);
        queryWrapper.orderByDesc(Employee::getUpdateTime);
        
        
        
        //会将查询出来的结果自动封装到 pageInfo中
        employeeService.page(pageInfo,queryWrapper);
        return R.success(pageInfo);
    }
package com.itheima.reggie.common;

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 java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;

/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 */
public class JacksonObjectMapper extends ObjectMapper {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    public JacksonObjectMapper() {
        super();
        //收到未知属性时不报异常
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

        //反序列化时,属性不存在的兼容处理
        this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);


        SimpleModule simpleModule = new SimpleModule()
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))

                .addSerializer(BigInteger.class, ToStringSerializer.instance)
                .addSerializer(Long.class, ToStringSerializer.instance)
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

        //注册功能模块 例如,可以添加自定义序列化器和反序列化器
        this.registerModule(simpleModule);
    }
}

对象映射器

1.继承json包中objectMapper类

2.WebMvcConfig中配置 拓展消息转换器

package com.itheima.reggie.common;

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 java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;

/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 */
public class JacksonObjectMapper extends ObjectMapper {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    public JacksonObjectMapper() {
        super();
        //收到未知属性时不报异常
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

        //反序列化时,属性不存在的兼容处理
        this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);


        SimpleModule simpleModule = new SimpleModule()
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))

                .addSerializer(BigInteger.class, ToStringSerializer.instance)
                .addSerializer(Long.class, ToStringSerializer.instance)
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
        //注册功能模块 例如,可以添加自定义序列化器和反序列化器
        this.registerModule(simpleModule);
    }
}

   /**
     * 扩展mvc框架消息转换器
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器启动");
        MappingJackson2HttpMessageConverter messageConverter=new MappingJackson2HttpMessageConverter();
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        converters.add(0,messageConverter);
    }

image-20220707114045190

公共字段自动填充

image-20220707114122872

在实体类中加入@TableField注解

package com.itheima.reggie.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;

@Data
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;

    private String username;

    private String name;

    private String password;

    private String phone;

    private String sex;

    private String idNumber;

    private Integer status;

    @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;


}

实现MetaObjectHandler

package com.itheima.reggie.common;

        import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
        import lombok.extern.slf4j.Slf4j;
        import org.apache.ibatis.reflection.MetaObject;
        import org.springframework.stereotype.Component;
        import java.time.LocalDateTime;

/**
 * 自定义元数据对象处理器
 */
@Component
@Slf4j
public class MyMetaObjecthandler implements MetaObjectHandler {
    /**
     * 插入操作,自动填充
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段自动填充[insert]...");
        log.info(metaObject.toString());
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("createUser",BaseContext.getCurrentId());
        metaObject.setValue("updateUser",BaseContext.getCurrentId());
        System.out.println(BaseContext.getCurrentId());
    }

    /**
     * 更新操作,自动填充
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自动填充[update]...");
        log.info(metaObject.toString());

        long id = Thread.currentThread().getId();
        log.info("线程id为:{}",id);


        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("updateUser",BaseContext.getCurrentId());
    }
}

文件的上传与下载

package com.itheima.reggie.controller;

import com.itheima.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.UUID;

@RestController
@Slf4j
@RequestMapping("/common")
public class CommonController {

    @Value("${reggie.path}")
    private String basePath;

    /**
     * 文件上传到服务器并保存到磁盘   就使用了一个MultipartFile file参数
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public R<String> upload(MultipartFile file) {
        String fileOriginalFilename = file.getOriginalFilename();
        String suffix = fileOriginalFilename.substring(fileOriginalFilename.lastIndexOf("."));
        String fileName = UUID.randomUUID() + suffix;

        File dir = new File(basePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try {
            file.transferTo(new File(basePath + fileName));
        } catch (IOException e) {

        }
        return R.success(fileName);

    }

    /**
     * 文件下载   谁创建某个流谁关闭  只有响应
     * @param name
     * @param response
     * @throws IOException
     */
    @GetMapping("/download")
    public void download(String name, HttpServletResponse response) throws IOException {

        InputStream fileInputStream = new FileInputStream(basePath + name);
        response.setContentType("image/jpeg");
        ServletOutputStream outputStream = response.getOutputStream();

        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = fileInputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, len);
            outputStream.flush();
        }
        fileInputStream.close();
    }
}

//浏览器接收到响应信息之后,默认情况下,直接在显示窗口中打开响应信息;即使打不开,也会调用应用程序打开;只有实在打不开,才会激活文件下载窗口。

//可以设置响应头信息,使浏览器接收到响应信息之后,直接激活文件下载窗口,即使能打开也打不开

response.addHeader("Content-Disposition","attachment;filename=mystudentList.xls");

attachment 附件

10.1.3 表单的编码格式只能用:multipart/form-data
<form action="workbench/activity/fileUpload.do" method="post" enctype="multipart/form-data">
  <input type="file" name="myFile"><br>
  <input type="text" name="userName"><br>
  <input type="submit" value="提交">
</form>

根据HTTP协议的规定,浏览器每次向后台提交参数,都会对参数进行统一编码;默认采用的编码格式是entype= "urlencoded",这种编码格式只能对文本数据进行编码;

浏览器每次向后台提交参数,都会首先把所有的参数转换成字符串,然后对这些数据统一进行urlencoded编码;对服务器传来的数据也通过这种方式进行解码 以前的提交的参数传输可以这么做,现在要传输文件了(传输二进制)就不能用这种编码方式

文件上传的表单编码格式只能用multipart/form-data:enctype="multipart/form-data" 功能:只是阻止默认行为

必须配置这个类 接受到文件上传请求后自动调用这个类

springboot默认有这个类

配置文件上传解析器 id:必须是multipartResolver 要不然会找不到

image-20220513152609084

查询菜品列表和套餐列表分别是type=1或type=2在 CategoryController 分别查询出来

前端菜品展示需要DishFlavor,所以返回的类型需要有DishFlavor

package com.itheima.reggie.dto;

import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;

@Data
public class DishDto extends Dish {

    private List<DishFlavor> flavors = new ArrayList<>();

    private String categoryName;

    private Integer copies;
}

/**
 * 返回菜品列表
 * @param dish
 * @return
 */
@GetMapping("/list")
public R<List<DishDto>> list(Dish dish) {

    List<DishDto> dishDtoList = null;
    String key = "dish_" + dish.getCategoryId() + "status_" + dish.getStatus();
    dishDtoList = (List<DishDto>) redisTemplate.opsForValue().get(key);

redis实现缓存验证码缓存用户信息

image-20220707114151840

redis实现缓存菜品

image-20220707114214435

springChace

image-20220621211439034

cacheable类似查询

Cacheput类似添加

cacheEvict类似删除

Nginx

image-20220707114242644

image-20220621211909839

image-20220707114304841

image-20220621212131595

不知道目标服务器的地址 ,适用于管理多台服务器,其他服务器在内网,就一个反向代理服务器提供一个端口和外网

image-20220621212401258

负载均衡器

image-20220621212552891

image-20220621212612409

mysql主从复制

image-20220707095336360

image-20220707095455082

实现读写分离

image-20220707095644882

image-20220707101719448

image-20220707101926761

server:
  port: 8080
spring:
  application:
    #可选 应用名称
    name: reggie_take_out

  shardingsphere:
    datasource:
      names:
        master,slave
      # 主数据源
      master:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.30.128:3306/reggie?characterEncoding=utf-8
        username: root
        password: root
      # 从数据源
      slave:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.30.129:3306/reggie?characterEncoding=utf-8
        username: root
        password: root
    masterslave:
      # 读写分离配置
      load-balance-algorithm-type: round_robin #轮询
      # 最终的数据源名称
      name: dataSource
      # 主库数据源名称
      master-data-source-name: master
      # 从库数据源名称列表,多个逗号分隔
      slave-data-source-names: slave
    props:
      sql:
        show: true #开启SQL显示,默认false
  main:
    allow-bean-definition-overriding: true

  redis:
    host: 192.168.30.128
    port: 6379
    password: 123321
    database: 0

mybatis-plus:
  configuration:
    #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      id-type: ASSIGN_ID


reggie:
  #反斜杠 创建路径
  path: /usr/local/img/

德鲁伊的数据源和sharingJDBC的数据源冲突,我们配置允许数据源覆盖即可

image-20220707103908710

image-20220707104218352

在yml配置文件中配置

image-20220707103946144

swagger

image-20220707112207761

image-20220707112359054

@Slf4j
@Configuration
@EnableSwagger2
@EnableKnife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @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();
    }

image-20220707112616571

/**
 * 静态资源映射
 * ("classpath:/backend/");    其中的/ 代表的是target
 * @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/");
}

image-20220707112719257

        //不需要拦截的路径
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**",
                "/user/login",
                "/user/sendMsg",
                "/doc.html",
                "/webjars/**",
                "/swagger-resources",
                "/v2/api-docs"
        };

image-20220707112954651

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
苍穹外卖项目可以使用Postman进行API接口的测试和调试。Postman是一款常用的API开发工具,它可以帮助开发人员发送HTTP请求并查看响应结果,方便进行接口的测试和调试。 在苍穹外卖项目中,可以使用Postman发送各种类型的HTTP请求,比如GET、POST、PUT、DELETE等,来模拟用户操作和测试接口功能。通过Postman,可以验证接口的正确性、查看接口返回的数据、调试接口的参数等。 为了使用Postman进行苍穹外卖项目的接口测试,您需要以下步骤: 1. 下载并安装Postman:您可以从Postman官网(https://www.postman.com/)上下载并安装适合您的操作系统的版本。 2. 打开Postman并创建一个新的请求:打开Postman应用,在界面上选择"New"来创建一个新的请求。 3. 输入接口URL和选择请求方法:在新建请求的界面中,输入苍穹外卖项目的接口URL,并选择适当的请求方法,比如GET或POST。 4. 添加请求参数和请求头:根据需要,您可以添加请求参数和请求头,以便于模拟不同的请求情况。 5. 发送请求并查看响应:点击发送按钮,Postman会向服务器发送请求,并在界面上显示响应结果。您可以查看接口返回的数据、响应状态码等信息。 通过以上步骤,您可以使用Postman进行苍穹外卖项目的接口测试。这样可以帮助您确保接口的正确性和稳定性,提高项目的质量和用户体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值