Java新手村《瑞吉外卖》笔记

文章讲述了在开发过程中,如何利用SpringBoot自动将Controller返回的对象转化为JSON格式,以及Java实体类实现序列化接口的作用。讨论了SpringBoot中@Service的注入方式和@RequestBody接收前端POST请求数据的用法。此外,还提到了Java中的session存储机制、ThreadLocal在存储用户ID中的应用,以及DTO对象在数据传输中的角色。同时涵盖了Git、Redis配置和使用的一些基本操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

瑞吉外卖笔记

1. Controller返回自定义对象自动转JSON格式

在开发项目的时候,返回给前端的数据,需要将数据封装到集合或者自定义对象中。但是前端需要的是JSON格式的字符串,如果我们将集合或者自定义对象直接返回给前端,前端无法接收到数据。

因此,我们需要将集合或者自定义对象转成JSON格式的字符串,每次使用代码进行转换有点繁琐,我们需要让Spring MVC自动帮我们将集合或者自定义对象转成JSON格式的字符串。
如果是Spring Boot项目,直接返回集合或者自定义对象即可,框架会自动将集合或者字符串自动转成JSON格式的字符串。

如果是SSM项目,使用@RestController或者@ResponseBody注解后,我们还需要添加配置,Spring MVC才能自动将集合或者自定义对象转成JSON格式。

原文链接:https://blog.csdn.net/weixin_44843569/article/details/118864444

2. java实体类中实现序列化接口有什么作用

3. 关于Springboot的@Service注入的方式

4. @RequestBody

@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的);而最常用的使用请求体传参的无疑是POST请求了,所以使用@RequestBody接收数据时,一般都用POST方式进行提交。

@PostMapping
   public R<String> save(HttpServletRequest request, @RequestBody Employee employee) {
       log.info("新增员工信息:{}", employee.toString());
       // 设置默认密码为123456 并进行MD5加密
       employee.setPassword(DigestUtils.md5DigestAsHex(CommonsConst.INIT_PASSWORD.getBytes()));
       //使用MybatisPlus的元对象处理器 自动填充公共字段 代理下面的代码:

       // 设置创建时间
       // employee.setCreateTime(LocalDateTime.now());
       // 设置更新时间
       // employee.setUpdateTime(LocalDateTime.now());
       // 用户ID设置(session中取得)
       // Long empId = (Long) request.getSession().getAttribute("employee");
       // employee.setCreateUser(empId);
       // employee.setUpdateUser(empId);
       // 调用存储方法
       employeeService.save(employee);
       return R.success("添加成功");
   }

5. Java中的session存储

  • 前端存储之sessionStorage和localStorage

  • sessionid是一个会话的key,浏览器第一次访问服务器会在服务器端生成一个session,有一个sessionid和它对应。tomcat生成的sessionid叫做jsessionid。

  • session在访问tomcat服务器HttpServletRequest的getSession(true)的时候创建,tomcat的ManagerBase类提供创建sessionid的方法:随机数+时间+jvmid。

  • 存储在服务器的内存中,tomcat的StandardManager类将session存储在内存中,也可以持久化到file,数据库,memcache,redis等。客户端只保存sessionid到cookie中,而不会保存session,session销毁只能通过invalidate或超时,关掉浏览器并不会关闭session。

  • 那么Session在何时创建呢?当然还是在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同创建Session的方法,而在Java中是通过调用HttpServletRequest的getSession方法(使用true作为参数)创建的。在创建了Session的同时,服务器会为该Session生成唯一的Session id,而这个Session id在随后的请求中会被用来重新获得已经创建的Session;在Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,而这些内容只会保存在服务器中,发到客户端的只有Session id;当客户端再次发送请求的时候,会将这个Session id带上,服务器接受到请求之后就会依据Session id找到相应的Session,从而再次使用之。

  • 创建:sessionid第一次产生是在直到某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建。

  • 删除:超时;程序调用HttpSession.invalidate();程序关闭。

  • session存放在哪里:服务器端的内存中。不过session可以通过特殊的方式做持久化管理(memcache,redis)。

  • session的id是从哪里来的,sessionID是如何使用的:当客户端第一次请求session对象时候,服务器会为客户端创建一个session,并将通过特殊算法算出一个session的ID,用来标识该session对象。

  • session会因为浏览器的关闭而删除吗?不会,session只会通过上面提到的方式去关闭。转载:session存到哪里

6. 公共字段填充

MybatisPlus 公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码;

实现步骤:

  1. 在实体类的属性上(需要自动填充的字段)加入@TableField注解,指定自动填充的策略;
  2. 按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现 MP提供的 MetaObjectHandler接口。

7. 将用户ID存入HttpSession改存入ThreadLocal,客户端同次请求下的操作可动态获取登录用户ID

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

在这里插入图片描述

  • ThreadLocal并不是一个Thread,而是Thread的一个局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都可以独立地改变自己的副本,而不影响其他线程所对应的副本。ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
    1. ThreadLocal ---->public void set(T value) 设置当前线程的线程局部变量的值;
    2. MetaObjectHandler ---->updataFill( ) 方法内就可以调用线程的get方法获取线程局部变量值。
  • 基于ThreadLocal封装工具类BaseContext,用户保存和获取当前登录用户id。
  • 工具类:里面的方法都定义为static 静态方法,通过工具类直接调用,注意这里就体现了单例模式的用法(饿汉单例):类第一次类加载就为了自己创建了一个实例对象,后续调用工具类的方法,都是同一个实例对象。
public class BaseContext {
    private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
    public static void setCurrentId(Long id){
        threadLocal.set(id);
    }
    public static Long getCurrentId(){
        return threadLocal.get();
    }
}
  • 具体流程:
  1. 在过滤器代码里就使用工具类存储用户id:
		//4-1 判断登陆状态,若已经登陆直接放行
        if (request.getSession().getAttribute("employee") != null) {
            log.info("用户已登录,id为:{}", request.getSession().getAttribute("employee"));

            //验证当前线程id
            Long empId = (Long) request.getSession().getAttribute("employee");
            BaseContext.setCurrentId(empId);

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

            filterChain.doFilter(request, response);
            return;
        }
        //若未登陆则返回未登陆结果
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
        return;
  1. 然后在元对象处理器(通过实现MybatisPlus的MeataObjectHandler接口,自动填充公共字段)里通过BaseContext获取线程局部变量值,从而获取”createUser“和”updateUser“的值:
@Component
@Slf4j
public class MyMetaObjecthandler implements MetaObjectHandler {
    @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());
    }
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自动填充[update]...");
        log.info(metaObject.toString());
        /*
         验证当前线程id
         long id = Thread.currentThread().getId();
         log.info("线程id为:{}",id);
        */
        metaObject.setValue("updateTime",LocalDateTime.now());
        metaObject.setValue("updateUser",BaseContext.getCurrentId());
    }
}

8. DTO

表现层与应用层之间是通过数据传输对象(DTO)进行交互的,数据传输对象是没有行为的POCO对象,它 的目的只是为了对领域对象进行数据封装,实现层与层之间的数据传递。为何不能直接将领域对象用于 数据传递?因为领域对象更注重领域,而DTO更注重数据。不仅如此,由于“富领域模型”的特点,这样 做会直接将领域对象的行为暴露给表现层。

需要了解的是,数据传输对象DTO本身并不是业务对象。数据传输对象是根据UI的需求进行设计的,而不 是根据领域对象进行设计的。比如,Customer领域对象可能会包含一些诸如FirstName, LastName, Email, Address等信息。但如果UI上不打算显示Address的信息,那么CustomerDTO中也无需包含这个 Address的数据

简单来说Model面向业务,我们是通过业务来定义Model的。而DTO是面向界面UI,是通过UI的需求来定义的。通过DTO我们实现了表现层与Model之间的解耦,表现层不引用Model,如果开发过程中我们的模型改变了,而界面没变,我们就只需要改Model而不需要去改表现层中的东西。
转载:我们为什么需要DTO(数据传输对象)

9. Git

在这里插入图片描述

10. Linux

复制文件到指定文件:

cp ./指定文件 指定文件目录

在这里插入图片描述

Vim 文本编辑器:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
查看进程:

在这里插入图片描述停止Tomcat服务的方式:
在这里插入图片描述

防火墙操作:
在这里插入图片描述
在这里插入图片描述

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

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

11. Redis

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

  • vim redis.conf 设置后台打开服务 ( daemonize yes)
    后续打开redis服务: src/redis-server ./redis.conf
  • vim redis.conf 设置需要密码 (requeirepass 123456)
    后续登录: src/redis-cli -h localhost -p 6379 -a 123456
    在这里插入图片描述
  • vim redis.conf 取消只能本地连接redis服务,然后就能远地连接redis服务。
    (将bind 127.0.0.1 注释掉) 同时还要把防火墙打开(
    开放指定端口:firewall-cmd --zone=public --add-port=6379/tcp --permanent
    立即生效:firewall-cmd --reload
    查看开放的端口: firewall–cmd --zone=public --list-ports
    最后还要重启服务:ps -ef | grep redis kill -9 [进程号] src/redis.server ./redis.conf
    )。
    在这里插入图片描述
    Redis中文教程
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

12. Redis缓存短信验证码

在这里插入图片描述

13. Redis缓存菜品数据

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

14. Spring Cache

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

15. MySQL 主从复制

在这里插入图片描述

16. Sharding-JDBC实现读写分离

在这里插入图片描述

17. Nigix

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

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

18. Swagger

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

19. 项目部署

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值