当前位置:   article > 正文

瑞吉外卖-项目要点总结

瑞吉外卖

一、对于返回参数这一块,配置了一个对象映射器,即将返回给前端的Java对象数据,序列化为字符串,在将前端传递的字符串数据反序列化Java对象。

项目中的问题:
后端在返回员工信息时,由于员工的id是Long类型,长度达到了19位,而前端JS能够处理的整数运算最多为正负2的53次方,也就是16位,也即从最小的值-9007199254740992到最大的值9007199254740992之间的范围,如果超过这个范围会进行四合五入,造成精度损失。
所以前端拿到的id是不准确的,如果我们后续修改用户时用的是这个不准确的id,必然是无法查询到数据的,所以为了解决这个问题,我们配置了一个Java对象和Json数据的转换器,在后端返回数据时,就将Long类型的id,转换为字符串,这样前端拿到的id就不会存在精度损失。
配置:

package com.dong.reggie.commom;
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);
  }
}
///
//在继承了WebMvcConfigurationSupport 类中重写extendMessageConverters方法,在该方法中指定我们的对象转换器。
package com.dong.reggie.config;
import com.dong.reggie.commom.JacksonObjectMapper;
import lombok.extern.slf4j.Slf4j;
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 java.util.List;

@Slf4j
@Configuration
public class WebMvcConfig  extends WebMvcConfigurationSupport {

  @Override
  protected void addResourceHandlers(ResourceHandlerRegistry registry) {
      log.info("开启静态资源映射");
      registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
      registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
  }
  @Override
  protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
      log.info("扩展消息转换器");
      //创建消息转换器
      MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter=new MappingJackson2HttpMessageConverter();
      //设置对象转换器
      mappingJackson2HttpMessageConverter.setObjectMapper(new JacksonObjectMapper());
      //将上面的消息转换器追加到MVC框架的转换器中
      converters.add(0,mappingJackson2HttpMessageConverter);
  }
}
  • 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

二、公共字段的自动填充

我们在对用户进行修改,添加时都会对一些字段进行修改,比如创建时间、修改时间、创建人、修改人等等,凡是大量的在插入或者修改数据库时,我们都需要手动进行设置之后在执行插入或者修改的字段,都可以理解为公共字段。
问题:如果每一次添加、修改的请求都需要对这些字段进行设置,会产生大量的冗余代码,而且会很浪费时间,重复性的操作太多。
解决方案:使用Mybatis-puls框架解决,实现MetaObjectHandler
实现:

package com.dong.reggie.commom;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;

@Component
public class MyMetObjectHandler implements MetaObjectHandler {
    /**
     * 添加数据,自动填充
     * @param metaObject //对应我们要操作的对象
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime",LocalDateTime.now());
        //如何获取当前用户的id?
        //使用ThreadLocal,ThreadLocal可以理解每一个线程单独的存储空间
        //在登录拦截中的doFilter,将当前用户的id存入ThreadLocal,在该方法中就可以使用threadlocal去获取该id
        //实现步骤,封装一个ThreadLocal工具类,在登录拦截器中保存id到ThreadLocal,获取id
        /**
         public class BaseoCntext {
         private static ThreadLocal<Long> threadLocal=new ThreadLocal<>();
         public static void setCurrentId(Long id){
         threadLocal.set(id);
         }
         public static Long getCurrentId() {
         return  threadLocal.get();
         }
         }
         */
        metaObject.setValue("createUser",BaseoCntext.getCurrentId());
        metaObject.setValue("updateUser",BaseoCntext.getCurrentId());
    }
    /**
     * 修改数据、自动填充
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("updateUser",BaseoCntext.getCurrentId());
    }
}
  • 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

最后一步,在实体类中需要自动填充的字段,添加注解相应注解,即可在进行插入、修改操作之前自动填充数据。
在这里插入图片描述

三、文件上下传

对于前端:
在这里插入图片描述
对于后端:
在这里插入图片描述
文件下载:
在这里插入图片描述
文件上传服务端代码:

package com.dong.reggie.controller;
import com.dong.reggie.commom.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
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 java.io.File;
import java.io.IOException;
import java.util.UUID;

@Slf4j
@RestController
@RequestMapping("/common")
public class CommonCtroller {
    @Value("${reggie.path}")
    private String basePath;
    @PostMapping("/upload")
    public R<String> uplod(MultipartFile file){
        log.info("接收到图片上传",file);
       // 截取原始文件名称的类型
        String originalFilename = file.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        //使用uuid生成新的文件名称,防止名称重复覆盖
        String fileName = UUID.randomUUID().toString()+suffix;
        //如果目录不存在,则创建目录
         File dir=new File(basePath);
         if(!dir.exists()){
             dir.mkdirs();
         }
        try {
            //转存接收到文件
            file.transferTo(new File(basePath+fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return R.success(fileName);
    }
}
  • 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

服务器端文件下载:

 @GetMapping("/download")
 	//name为文件名称
    public void downLoad(HttpServletResponse response, String name) {
        FileInputStream in = null;
        ServletOutputStream out = null;
        try {
            //构建文件输入流,读取保存的图片
            in = new FileInputStream(new File(basePath + name));
            //构建输出流,输出图片信息
            out = response.getOutputStream();
            //设置响应流格式
            response.setContentType("image/jpeg");
            //写入图片数据
            int len = 0;
            byte[] bytes = new byte[1024];
            //读入数据到byte数组
            while ((len = in.read(bytes)) != -1) {
                //从byte数组写出数据
                out.write(bytes, 0, len);
                out.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if(in!=null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(out!=null){
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  • 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

四、短信发送

在这里插入图片描述
依赖

        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.5.16</version>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
            <version>2.1.0</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

短信发送工具类

package com.dong.reggie.utils;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;

/**
 * 短信发送工具类
 */
public class SMSUtils {
	/**
	 * 发送短信
	 * @param signName 签名
	 * @param templateCode 模板
	 * @param phoneNumbers 手机号
	 * @param param 参数
	 */
	public static void sendMessage(String signName, String templateCode,String phoneNumbers,String param){
		DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "", "");
		IAcsClient client = new DefaultAcsClient(profile);
		SendSmsRequest request = new SendSmsRequest();
		request.setSysRegionId("cn-hangzhou");
		request.setPhoneNumbers(phoneNumbers);
		request.setSignName(signName);
		request.setTemplateCode(templateCode);
		request.setTemplateParam("{\"code\":\""+param+"\"}");
		try {
			SendSmsResponse response = client.getAcsResponse(request);
			System.out.println("短信发送成功");
		}catch (ClientException e) {
			e.printStackTrace();
		}
	}
}
  • 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

生成四位数字验证码工具类

package com.dong.reggie.utils;
import java.util.Random;

/**
 * 随机生成验证码工具类
 */
public class ValidateCodeUtils {
    /**
     * 随机生成验证码
     * @param length 长度为4位或者6位
     * @return
     */
    public static Integer generateValidateCode(int length){
        Integer code =null;
        if(length == 4){
            code = new Random().nextInt(9999);//生成随机数,最大为9999
            if(code < 1000){
                code = code + 1000;//保证随机数为4位数字
            }
        }else if(length == 6){
            code = new Random().nextInt(999999);//生成随机数,最大为999999
            if(code < 100000){
                code = code + 100000;//保证随机数为6位数字
            }
        }else{
            throw new RuntimeException("只能生成4位或6位数字验证码");
        }
        return code;
    }

    /**
     * 随机生成指定长度字符串验证码
     * @param length 长度
     * @return
     */
    public static String generateValidateCode4String(int length){
        Random rdm = new Random();
        String hash1 = Integer.toHexString(rdm.nextInt());
        String capstr = hash1.substring(0, length);
        return capstr;
    }
}
  • 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

五、Redis缓存搭建

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
  • 1
  • 2
  • 3
  • 4

配置Redis

  redis:
    port: 6379
    host: localhost
    database: 0
  • 1
  • 2
  • 3
  • 4

配置类,设置序列化器

@Configuration
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory connectionFactory){
        RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<>();
        //设置Redis Key的默认序列化器
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(connectionFactory);
        return  redisTemplate;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在相应的业务逻辑中,使用缓存

        //保存验证码,缓存到Redis中
        redisTemplate.opsForValue().set(phone,code,5,TimeUnit.MINUTES);
        //从redis中取出数据
        redisTemplate.opsForValue().get(phone);
        //从redis中删除数据
        redisTemplate.delete(phone);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意:如果项目中使用了缓存,一定要注意数据库和缓存中的一致性问题,该项目中解决该问题的处理方式比较简单,不够全面。

六、Spring Cache

在这里插入图片描述
在这里插入图片描述
使用Spring Cache,底层使用Redis

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在启动类上添加注解@EnableCaching注解,开启缓存注解。在Controller方法上添加@Cacheable,@CacheEvict等注解

七、读写分离

配置多个数据库,一个为写库,一个为读库,降低单台数据库的访问压力。需要解决不同数据库之间的数据同步问题。

MySQL的主从复制

主库为写库,从库为读库
MySQL的主从复制实际上就是其他的数据库(从库)获取一台数据库(主库)的日志,并对该日志解析然后自己照着解析的日志操作一遍,比如解析出两条insert、一条update语句,那从库也会去执行这些语句,从而达到从库和主库数据同步的效果,并且主从复制是MySQL自带的功能,不需要借助第三方工具。
MySQL复制过程分成三步

  • 主库(master)将改变记录到二进制日志(binary log)
  • 从库(slave)将主库的二进制文件拷贝到它的中继日志(relay log)
  • 从库(slave)重做中继日志中的事件,将改变应用到自己的数据库中

配置MySQL主从复制

想要配置主从配置,毫无疑问,需要两个mysql,也就说需要两个服务器,这里我使用Linux中的mysql,来实现主从复制
主库IP:192.168.248.110
从库ip:192.168.248.111

主库:
1、修改master数据库的配置文件/etc/my.cnf

log-bin=mysql-bin  #启用二进制文件
server-id=100   #服务器唯一id
  • 1
  • 2

2、重启mysql服务 systemctl restart mysqld
3、创建一个用于从库和主库通信的用户
执行下面的sql

grant replication slave on *.* to ‘xiaoming’@'%' identified by ‘Root@123456’;
  • 1

该sql的作用是创建一个用户xiaoming,密码为Root@123456,并且给xiaoming用户授予replication slave权限。slave必须被master授予具有该权限的用户,才能通过该用户去进行复制。
4、
在这里插入图片描述
从库:
1
在这里插入图片描述
2.重启服务
3
在这里插入图片描述
4
在这里插入图片描述
若配置完,发现slave_id_running为 no,这些因为克隆的原因,导致两个mysql的uuid相同。
在这里插入图片描述
此时,删除任意一个mysql的autu.cnf文件,让它从新生成新的uuid即可。
rm -rf /var/lib/mysql/auto.cnf
删除之后记得重启服务,建议连个mysql都重启一次 stytemctl restart mysqld
之后等一会再次在slave中运行 show slave status,就会发现slave_id_running变为 yes。
此时mysql的主从复制配置已经完成,可以在主库中添加数据测试一下从库是否同步。

实现读写分离

Sharding-JDBC
Sharding-JDBC定位为轻量级java框架、在java的jdbc层提供额外的服务。它能使客户端直连数据库。以jar包的形式提供服务,无需额外部署和依赖,可理解为增强版的jdbc驱动,完全兼容jdbc和各种orm框架。
使用Sharding-JDBC可以在程序中轻松的实现读写分离。
在这里插入图片描述

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

使用Sharding-jdbc实现读写分离
1、导入Maven坐标
2、在配置文件中配置读写分离规则
3、在配置文件中配置允许Bean自定义覆盖配置项

server:
  port: 8081
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: E:\reggieImg\
spring:
  application:
    name: reggie_take_out
  redis:
    port: 6379
    host: localhost
    database: 0
  cache:
    redis:
      time-to-live: 1800000 #设置缓存有效期
      
   ##配置读写分离
  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.248.110:3306/reggie?characterEncoding=utf-8
        username: root
        password: ******
      # 从数据源
      slave:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.248.111:3306/reggie?characterEncoding=utf-8
        username: root
        password: ********
    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
  • 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

启动项目就可以看见其创建了两个数据源
在这里插入图片描述
至此,我们就实现了读写分离,我们的java源代码不需要进行任何修改。
可以测试一下:
查询:可以看到查询走的是我们的从节点,也及时slave
在这里插入图片描述
新增:
在这里插入图片描述

八、Nginx的安装和使用

在这里插入图片描述

安装环境

 yum -y install gcc pcre-devel zlib-devel  openssl openssl-devel
  • 1

从官网下载NGINX 官网地址:nginx.org
在这里插入图片描述
安装完成。
在这里插入图片描述
在这里插入图片描述
Nginx命令:

命令功能
./nginx -v查看版本号
./nginx -t检查配置文件conf/nginx.conf是否存在错误
./nginx启动nginx
./nginx -s stop停止nginx服务
ps -ef | grep nginx查看ngin相关的进程
./nginx -s reload重新加载配置文件

配置环境变量 vi /etc/profile
在这里插入图片描述
然后从新加载一下配置文件 source /etc/profile

配置文件

在这里插入图片描述

Nginx的应用

  • 部署静态资源
    • Nginx可以作为静态的Web服务器来部署静态资源,包括Html页面、css文件、js文件、图片、视屏等
    • 将静态资源部署Nginx到服务器上很简单,只需要将文件复制到Nginx安装目录下的html目录即可
      在这里插入图片描述
  • 反向代理
    • 可以理解为反向代理服务器取代了目标服务器,也就说用户不知道目标服务器的存在,用户的请求都发到反向代理服务器上,由反向代理服务器去转发用户的请求到目标服务器。好处就是便于管理,提供统一的一个请求地址,就算存在多个服务器,也只需访问反向代理服务器的地址即可。
      在这里插入图片描述
  • 负载均衡
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

九、YApi 接口开发工具

用于定义接口
在这里插入图片描述

Swagger

在这里插入图片描述
在这里插入图片描述

        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>3.0.2</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

配置knife4j

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);
    }
//配置Swagger
    @Bean
    public Docket createRestApi() {
        // 文档类型
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.dong.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

放行路径
在这里插入图片描述
启动项目,即可看见接口文档
在这里插入图片描述

Swagger常用注解

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

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/650479
推荐阅读
相关标签
  

闽ICP备14008679号