瑞吉外卖实战-笔记

软件开发的流程
瑞吉外卖实战-笔记_第1张图片

角色分工
瑞吉外卖实战-笔记_第2张图片

软件环境
瑞吉外卖实战-笔记_第3张图片

开发环境的搭建

数据库环境

maven环境
1.创建完成后,需要检查一下编码、maven仓库、jdk等

<parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.7.12</version>
</parent>
//注意:3.0版本以下使用的java版本是11,

2.导入pom

 <dependencies>
<!--sb的起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
<!--sb的测试依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
<!--springboot的web使用依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>compile</scope>
        </dependency>
<!--mybatisplus的起步依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
<!--json数据包-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>

        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
<!--数据库的驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
            <version>8.0.33</version>
        </dependency>
<!--数据源的依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.23</version>
        </dependency>
<!--阿里云的短信服务-->
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>4.0.3</version>
        </dependency>

        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
            <version>1.1.0</version>
        </dependency>
    </dependencies>

    <build>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.4.5</version>
</plugin>
</plugins>
</build>

1.Filter-过滤器

作用:用于登录校验,未登录禁止访问

@WebFilter(filterName = "EmployeeLoginFilter",urlPatterns = "/*"),申明过滤器,名称自取,拦截路径为所有路径
想要使用过滤器,需要在启动类添加 @ServletComponentScan 注解

实现逻辑

  1. 创建一个类,实现Filter
  2. 重写doFilter方法
  3. 定义放行的路径数组
String[] url=new String[]
{ "/employee/login","/employee/logout","/common/**","/user/sendMsg","/user/login","/backend/**","/front/**"
};
//"/employee/login","/employee/logout"这是controller中的路径
//"/backend/**""/common/**",静态资源路径,即前端页面代码,路径从resources第一个包开始

4.获取前端请求路径,与以上的放行路径进行对比

HttpServletRequest httpServletRequest= (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse= (HttpServletResponse) servletResponse;
String requestURI = httpServletRequest.getRequestURI();//获取前端请求路径

5.遍历对比信息

public static final AntPathMatcher antPathMatcher=new AntPathMatcher();//路径对比器
public boolean pathmatch(String[] url,String requesturl)//自定义对比方法
    {
        for (String path:url
             ) {
            boolean match = antPathMatcher.match(path, requesturl);
            if(match)
            {
                return true;
            }
        }
        return false;
    }

6.调用自定义的方法,boolean pathmatch = this.pathmatch(url, requestURI);如果为true,则匹配成功,放行, filterChain.doFilter(httpServletRequest,httpServletResponse);这两个参数为doFilter的参数
7.如果没有进行前后端分离的话,在跳转到登录命令的controller后,需要设置一个session属性,用于判断是否登录

//Longincontroller,方法中需要自定义一个HttpServletRequest对象
request.getSession().setAttribute("employee",one.getId());

8.判断session是否存在,不存在则表示未登录
Object employee = httpServletRequest.getSession().getAttribute(“employee”);

2.MybatisPlus的分页查询-Pageconfig

作用:自定义分页,无需手动构造分页内容

@Configuration
public class PageConfig {

    @Bean
   public MybatisPlusInterceptor mybatisPlusInterceptor()
   {
       MybatisPlusInterceptor mybatisPlusInterceptor=new MybatisPlusInterceptor();
       mybatisPlusInterceptor.addInnerInterceptor( new PaginationInnerInterceptor());
       return mybatisPlusInterceptor;
   }
}
//通过Page<Object> page=new Page<>(起始页,每页条数)可直接使用

3.公共字段填充-MetaObjectHander

作用:数据表发生变化时,自动添加某些字段

实现逻辑
1.自定义类实现MetaObjectHandler类
2.重写insertFill方法/updateFill方法
3.添加公共参数

metaObject.setValue("updateTime", LocalDateTime.now())//第一个参数为数据表字段名称;

4.MybatisPlus

作用:mybatis的升级,不用手动编写sql

注意:使用mybatisplus,数据层与业务层有所不同

`
//数据层
@Mapper
public interface Mapper extends BaseMapper<实体类名>
//业务层接口
public interface Service extends IService<实体类名> {}
//业务层实现类
@Service
public class ServiceImpl extends ServiceImpl<Mapper,实体类名> implements Service {}`

想要使用mybatisplus自带的命令
1.构造一个条件对象
LambdaQueryWrapper<实体类> queryWrapper=new LambdaQueryWrapper<>();查找条件
LambdaUpdateWrapper<实体类> updateWrapper=new LambdaUpdateWrapper<>();条件更新
2.通过条件对象进行sql操作

5.数据传输对象-Dto

作用:将多个表单对象封装到一起,用于前端展示
步骤
1.创建表单类A、B
2.自定义一个类,继承A类
3.在自定义类中定义其他属性(集合/字符串/整形等)
4.集合中的参数为表单类B

@Data
public class DishDto extends Dish {

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

    private String categoryName;

    private Integer copies;
}

6.后端响应结果集

将后端的发送的数据进行封装,在前端页面展示

//结果类包含的内容
private Integer code;//用于表示后端处理成功或失败
private String msg;//用于对后端处理结果的描述
private T data;//定义一个泛型,用于将后端处理后的数据传到前端

自定义泛型类
public class R<T> {
    // 类成员和方法的定义
}

泛型类的构造方法,返回值是一个泛型
public static <T>R<T>success(T obj)
    {
        R<T> r=new R<T>();
        r.data=obj;
        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;
    }

7.自定义异常类

作用:捕获后端异常,当后端发生异常时,能够及时通知到前端

1.自定义异常类
//根据需要,继承想要展示的异常
public class CustomException extends RuntimeException{
public CustomException(String msg)
{
super(msg);		//调用父类的构造方法
}
}

2.定义异常处理类-ExceptionHandler
//@RestControllerAdvice通常与ExceptionHandler注解连用
@RestControllerAdvice(annotations = RestController.class)//=@Responsebody+@ControllerAdvice,参数为被拦截的错误来源
@Slf4j
public class ExceptionHandler {
    @org.springframework.web.bind.annotation.ExceptionHandler(CustomException.class)//处理异常类
    //SQLIntegrityConstraintViolationException e
    public R<String> ex(SQLIntegrityConstraintViolationException e)
    {
    log.info("异常处理");
    if(e.getMessage().contains("Duplicate entry"))//e.getmessage,就能获取到自定义错误的信息
    {
        System.out.println(e.getMessage());
        String[] errstr= e.getMessage().split(" ");
        for (String s:errstr
             ) {
            System.out.println(s);
        }
        String msg=errstr[2]+"已存在";
        log.info(msg);
        return R.error(msg);
    }
    return R.error("失败了");
    }

8.多线程-ThreadLocal

作用
1.跟踪请求处理过程中的数据:如将用户的标识(比如用户ID)存储在 threadLocal 中,这样在整个请求处理过程中都可以方便地获取和使用它
2.线程隔离的数据存储:一些数据在多线程环境中是线程私有的,并且不同线程之间的数据不应该相互干扰,可以使用 ThreadLocal 来实现数据的线程隔离。

//一般在校验登录的时候就为其赋值,将初始化的session赋给threadLocal,对象.方法调用即可
public class BaseContext {
    private static ThreadLocal<Long> threadLocal=new ThreadLocal<>();//通过这个方法就能随时获取sessionid,不用构建HttpServletRequest参数对象
    public static void setThreadLocal(Long integer)
    {
        threadLocal.set(integer);
    }
    public static Long getThreadLocal()
    {
        return threadLocal.get();
    }
}

10.文件上传下载-文件存储与本地,数据库只存储文件名

文件上传
1.获取上传的文件后缀名称
2.生成唯一的文件名称
3.校验存储位置的文件夹是否存在
4.转存到对应的文件夹

@Value("${reggie.path}")//配置文件自定义文件夹路径
    private String path;
    @PostMapping("/upload")
    public R<String> upload(MultipartFile file) throws IOException //上传的文件对象参数名,必须与前端的input框的name名字一致,且文件对象必须是MultipartFile
    {
        //上传的file文件是一个临时文件,需要转存,不然本次操作后,该文件就会销毁消失
        String originalFilename = file.getOriginalFilename(); //获取文件上传时的名称
        log.info(originalFilename);
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));//获取上传文件的后缀
        log.info(file+"这是前端的对象信息");
        String filename = UUID.randomUUID().toString()+suffix;//UUID生成一个唯一的名字
        log.info(filename);
        /**
         * 判断配置文件 @Value("${reggie.path}")的目录是否存在,没有就创建
         */

        File dir=new File(path);
        log.info("dir"+dir);
        if(!dir.exists())
        {
            log.info("创建文件");
            dir.mkdirs();//创建@Value("${reggie.path}")的文件夹
        }

        file.transferTo(new File(path+"/"+filename));   //将临时文件转存到该路径
        return R.success(filename);
    }

文件下载

@GetMapping("/download")
    public void download(String name, HttpServletResponse response)//name为图片存储地址
    {
        //下载文件需要经过两个步骤,读数据流,写数据流
        try {
            FileInputStream fileInputStream=new FileInputStream(new File(path+"/"+name));//输入流,将文件地址写入
            ServletOutputStream outputStream = response.getOutputStream();//输出流,因为这里需要将数据流显示到前端,所以用HttpServletResponse
            response.setContentType("image/jpeg");//设置传输到前端的数据格式
            int len=0;
            byte[] bytes=new byte[1024];
            while((len=fileInputStream.read(bytes))!=-1)//len是每次读取的字节数,bytes是存储读出字节的内容,fileInputStream.read是读取输入流,当读取完最后一个数时,len=-1
            {
                outputStream.write(bytes,0,len);//输出流,outputStream = response.getOutputStream(),写入bytes数组中的内容,从0开始写入,长度是len
                outputStream.flush();//刷新数据流
            }
            outputStream.close();//关闭输出流
            fileInputStream.close();//关闭输入流
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

你可能感兴趣的:(实战项目笔记,笔记,java)