瑞吉外卖笔记
文章目录
- 瑞吉外卖笔记
- 1. Controller返回自定义对象自动转JSON格式
- 2. [java实体类中实现序列化接口有什么作用](https://www.cnblogs.com/wjune-0405/p/12636326.html)
- 3. [关于Springboot的@Service注入的方式](https://blog.csdn.net/BAStriver/article/details/103671096)
- 4. @RequestBody
- 5. Java中的session存储
- 6. 公共字段填充
- 7. 将用户ID存入HttpSession改存入ThreadLocal,客户端同次请求下的操作可动态获取登录用户ID
- 8. DTO
- 9. Git
- 10. Linux
- 11. Redis
- 12. Redis缓存短信验证码
- 13. Redis缓存菜品数据
- 14. Spring Cache
- 15. MySQL 主从复制
- 16. Sharding-JDBC实现读写分离
- 17. Nigix
- 18. Swagger
- 19. 项目部署
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存储
-
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 公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码;
实现步骤:
- 在实体类的属性上(需要自动填充的字段)加入@TableField注解,指定自动填充的策略;
- 按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现 MP提供的 MetaObjectHandler接口。
7. 将用户ID存入HttpSession改存入ThreadLocal,客户端同次请求下的操作可动态获取登录用户ID
- ThreadLocal并不是一个Thread,而是Thread的一个局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都可以独立地改变自己的副本,而不影响其他线程所对应的副本。ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
-
- ThreadLocal ---->public void set(T value) 设置当前线程的线程局部变量的值;
- 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();
}
}
- 具体流程:
- 在过滤器代码里就使用工具类存储用户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;
- 然后在元对象处理器(通过实现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. 项目部署