Java后端核心知识速记笔记 —— Maven + Spring IOC + MVC + MyBatis 一站式总结(附代码示例)
- maven
- Request和Response区别
- Spring依赖注入
- 概念解释
- 常见注解
- Spring Resource
- 不同路径文件读方法
- Spring MVC
- 概念解释
- 常见注解
- Spring Session
- 流程
- 传统 HttpSession版
- Redis版
- 拦截器
- 配置拦截器
- Mybatis
- 概念解释
- 常见注解
- 流程
- 代码示例
- 整体链路
- 实战
maven
- maven坐标:用于唯一标识一个Jar/项目,方便从仓库下载依赖。
<groupId>org.example</groupId>//组织/公司/个人的ID(使用反域名形式)<artifactId>java_maven_test</artifactId>//项目的ID<version>1.1.2-SNAPSHOT</version>//代码的版本- 一个pom.xml文件里只能有一个<dependencies> </dependencies> ,可以有多个<dependency></dependency>
- maven会强制所有java项目的结构一样
- src/main/java:放源码
- src/main/resources:放配置文件
- src/test/java:放单元测试的代码
- pom.xml:定义项目坐标。依赖管理。构建与生命周期控制
Request和Response区别
- 在网络传输的角度,Request(请求)表示客户端(浏览器/App)向服务器发送需求和数据,例如访问地址、提交表单、携带参数等;Response(响应)表示服务器处理完请求后返回结果,例如页面内容、JSON 数据、状态码或 Cookie。
- 在后端代码角度,Request 用来读取用户传来的信息,Response 用来向客户端输出处理结果,本质上就是Request 负责输入,Response 负责输出。
- 物理层面:Request 是前端发来的数据包,Response 是后端发回去的数据包。
- 逻辑层面:Request 是你的输入参数,Response 是你的返回结果。
- HTTP层面:Request和Response是一来一回成对出现的。
Spring依赖注入
概念解释
- Bean:指的是放在Spring容器里的对象,有生命周期,作用域和依赖注入等特性(可通过接口引用实现多态)
- IOC(控制反转):一个思想,把对象的创建交给Spring容器来控制,而不是程序员自己
- 依赖:A类里需要B类的实例,那么就说B是A类的依赖
- 依赖注入:由 Spring 容器统一调度,将 A 类所依赖的 B 实例,在 A 实例创建时自动交给 A 的过程。这样就不需要自己去new对象了
常见注解
- @Bean(方法级别注解):把注解方法执行后的返回值交给Spring容器
- @Autowired(属性级别注解):注入依赖
- @Component(类级别注解):将当前类标记为一个Spring Bean,实现IOC。Spring 启动时,由
Component Scan机制扫描到带此标签的类,并自动实例化(new)放入 Spring 容器。- @service:告诉Spring这是一个业务类。@Component语义化注解,下面也是
- @Controller:这是Controller层的类,负责接收 HTTP 请求、处理用户输入并返回响应,与前端交互
- @Repository:DAO层(数据访问层)。现在用MyBatis时,@Mapper基本可完全替代它
- @Configuration:将当前类标记为一个Spring Bean,实现IOC。告诉Spring这是一个配置类
- @PostConstruct(方法级别注解):标记在非静态、无参、返回值为 void的实例方法上,由 Spring 容器在完成@Autowired 依赖注入后自动触发运行一次,可以放一些初始化的代码
- 一般来说,@Bean用于第三方类/手动配置对象,@Component用于自己写的类
Spring Resource
不同路径文件读方法
- 在电脑本地(绝对路径),路径比如:
d:/mywork/a.md- 直接通过File读写: `File file=new File(“d:/mywork/a.md”);
- 在工程目录下(含有 pom.xml 的位置):
mywork/lantian.png- 和第一种情况一样
- 在
src/main/resources的目录下的文件- 通过ResourceLoader去读文件(不能写文件),resources目录内容最终会被打包进classpath(这也是为什么会有前缀classpath)。
- 要使用try-with-resources的写法(把流的创建写在try后的括号里),这样可以在执行完代码后关闭流
- 下面这段代码可以读以上三种路径的文件+URL路径文件,注意不同文件路径的前缀可能不同
| 位置 | 读取方式 | 前缀示例 |
|---|---|---|
项目内resources/ | ResourceLoader / ClassPath | classpath:xxx.properties |
| 绝对路径 | file: | file:D:/data/xxx.txt |
| 远程URL | http:/https: | https://... |
@ServicepublicclassFileServiceImplimplementsFileService{@AutowiredprivateResourceLoaderloader;@OverridepublicStringgetContent(StringpathName){// 1. "classpath:config.txt" (resources下)// 2. "file:C:/temp/test.txt" (绝对路径,工程目录下)// 3. "https://example.com/api.json" (远程资源)try(InputStreamin=loader.getResource(pathName).getInputStream()){returnIOUtils.toString(in,"utf-8");}catch(IOExceptione){returnnull;}}}Spring MVC
概念解释
- Session:服务器端用来存储用户数据的机制,Session默认有超时时间(如30分钟),浏览器关闭不一定失效。
- Session ID:这是连接用户的唯一凭证,通常通过 Cookie 返回给浏览器。
- Cookie(可长期存储):服务器发送并存储在浏览器上的一小段文本数据,随后的每次 HTTP 请求都会将其自动携带并发送回服务器。(里面有session ID)
- Cookie存客户端,小而轻;Session存服务端,安全但占资源。
- Cookie的属性
| 属性维度 | 属性名称 | 示例值 | 核心作用与描述 |
|---|---|---|---|
| 基础数据 | Name | SESSION | Cookie 的名称,不区分大小写,但建议保持一致。 |
| Value | abc123xyz | 存储的数据内容,通常是加密后的 SessionID 或 Token。 | |
| 生命周期 | Expires | Wed, 22 Oct 2026... | 绝对过期时间。到达该 GMT 时间点后,浏览器会删除该 Cookie。 |
| Max-Age | 3600 | 相对有效期(秒)。从浏览器收到开始计算。优先级高于Expires。 | |
- | 若不设置上述两项,则为会话 Cookie,浏览器关闭后立即消失。 | ||
| 作用范围 | Domain | example.com | 指定哪些域名可以接收此 Cookie。不设则默认为当前域名(不含子域名)。 |
| Path | / | 指定哪些路径下的请求可以带上此 Cookie。通常设为/表示全站通用。 | |
| 安全性 | HttpOnly | true/false | 最重要。设为true后,JS 脚本无法通过document.cookie读取,防 XSS 攻击。 |
| Secure | true/false | 设为true后,该 Cookie 只能通过HTTPS协议传输,防明文监听。 | |
| 跨站策略 | SameSite | Lax(默认) | 防 CSRF 攻击。控制第三方网站请求时是否携带该 Cookie(Strict/Lax/None)。 |
常见注解
- @Controller(类级别注解):告诉Spring,这是一个处理http请求的类。默认通过返回字符串来跳转到对应的 HTML 页面模板。
- @RequestMapping(类/方法级别注解):括号里定义访问路径,注解的代码块去处理request请求
- @GetMapping(方法):专门用于处理Get请求
- @PostMapping(方法):专门用于处理Post请求
- @RequestParam(方法参数):用于提取URL里的参数(不是定义参数),如
?id=1 - @ResponseBody(类/方法):告诉Spring把方法返回的结果(如果返回的是普通字符串,它就直接返回原文本;如果返回的是对象,它会通过
Jackson库转为JSON。传送给前端(浏览器),而不用去找HTML页面模板 - @RequestBody:用于接收HTTP 请求体中的 JSON 数据,Spring 会将 JSON 自动反序列化为Java 对象(通常是 DTO),并注入到方法参数中。
- @RestController(类)=@Controller+@ResponseBody
Spring Session
流程
传统 HttpSession版
- 第一次请求:浏览器发送请求(没有 Cookie),服务器收到后配置session后发送响应(携带Set-Cookie: JSESSIONID=abc123(这个是告诉浏览器去创建对应的cookie)),浏览器接收到后自动保存这个cookie
- 第n次请求:浏览器发送请求(携带Cookie: JSESSIONID=abc123),服务器接收到Cookie 里的 JSESSIONID后去对应的session对象
- 如果 Session 未过期,则继续使用其中的数据(如登录状态)。
- 如果已过期,则重新创建新的 Session,并返回新的 Cookie。
- 浏览器保存 SessionID,Redis保存 Session 数据。
Redis版
- 第一次请求:在地址框输入URL后,浏览器发送请求(请求里没有Cookie)。后端创建 Session,并生成 SessionID,将Session数据存入Redis。响应浏览器(
set-Cookie :=SESSION=abc123)。浏览器保存这个Cookie - 第n次请求:在地址框输入URL后,浏览器请求含有这个URL对应的Cookie(包含SessionID)。后端根据传来的SessionID,去redis里找对应的数据
- 如果 Session 未过期,则恢复登录状态、用户信息等。
- 如果已过期,则创建新的 Session,并返回新的 Cookie。
- 浏览器保存 SessionID,Redis保存 Session 数据。
拦截器
- Spring MVC 拦截器用于在 Controller 前后执行公共逻辑。
- 核心接口:
HandlerInterceptor - 通过实现
HandlerInterceptor接口,可重写preHandle、postHandle、afterCompletion
常用于登录校验、权限控制、日志记录等。 - 执行顺序:preHandle() -> Controller -> postHandle() -> 页面渲染 -> afterCompletion()
publicclassLoginInterceptorimplementsHandlerInterceptor{// Controller方法执行之前,这里是登录校验@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{Objectuser=request.getSession().getAttribute("user");if(user==null){response.sendRedirect("/login");returnfalse;}returntrue;}//Controller方法执行之后@OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{}// 整个请求完成后(包括渲染完毕)@OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{}}配置拦截器
现在你有了拦截器,但它们不会自动生效。你需要告诉Spring MVC去使用这些拦截器。这就是WebMvcConfigurer接口的作用。
@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@Override//这里InterceptorRegistry是spring框架内部的工具类publicvoidaddInterceptors(InterceptorRegistryregistry){// 注册你的拦截器registry.addInterceptor(newLoginInterceptor())// 指定拦截哪些路径(支持通配符).addPathPatterns("/**")// 指定排除哪些路径.excludePathPatterns("/static/**","/js/**","/css/**");// 你可以注册多个拦截器,它们会按注册顺序执行registry.addInterceptor(newAuthInterceptor()).addPathPatterns("/api/**");}}- 总结:拦截器解三个相关的类/接口
HandlerInterceptor接口:编写拦截逻辑的接口。需要实现其中的方法(如preHandle()、postHandle()、afterCompletion())。WebMvcConfigurer接口:Spring MVC 的扩展配置接口,用于注册拦截器等配置。InterceptorRegistry类:spring框架内部的工具类,通过这个类实现对拦截器的管理(通过它来设置拦截器的拦截路径(addPathPatterns)和排除路径(excludePathPatterns))
Mybatis
概念解释
- DAO层(Mapper层):负责与数据库交互,执行增删改查操作。在 MyBatis 中通常体现为 Mapper 接口及其对应 SQL 映射。
- DO层:用于映射数据库表结构的对象,属性通常对应表字段,主要用于数据持久化。
- **DTO层 ** :数据传输对象。主要用于 Service 层和 Controller 层之间的数据传递。比如:注册时前端传来的字段很多,但你只需要其中几个存入数据库。
- VO:显示层对象。专门用于封装返回给前端页面展示的数据。
- Service层:负责核心业务逻辑处理。
- Controller层:负责接收前端请求、调用 Service 层处理业务,并将结果返回给前端。
- XML 映射文件:可以把 SQL 语句写在
.xml文件中。 - ResultMap:解决数据库字段名与 Java 属性名不一致的问题。
- 动态SQL:根据条件动态生成 SQL,常用
<if>、<where>、<foreach>。 - #{ }:预编译参数,占位安全。
- ${ }:字符串替换。有SQL注入风险(一般不使用了)。
常见注解
- @Mapper:将 MyBatis 的 Mapper接口标记为 Spring 可识别并管理的Bean,从而生成其代理对象,用于执行数据库操作。
流程
- Request: 前端发送请求。
- Controller: 接收请求,将参数封装进DTO。
- Service: 执行业务逻辑(比如:查一下余额够不够,再决定扣钱)。
- Mapper (DAO): Service 调用 Mapper 接口。
- MyBatis 底层: 匹配 XML 里的 SQL,将DO对象里的数据持久化到数据库。
- Response: 数据库返回结果 -> 转换成VO-> Controller 返回给前端。
代码示例
- DO层:
publicclassUserDO{privateLongid;privateStringuserName;privateStringuserEmail;// 故意与数据库字段名 user_email 不一致,用于演示 resultMapprivateIntegerstatus;// Getter, Setter, NoArgsConstructor...}- DAO层:
@MapperpublicinterfaceUserMapper{// 演示 insertintinsertUser(UserDOuser);// 演示 select, if (动态条件查询)List<UserDO>selectUsers(@Param("name")Stringname,@Param("status")Integerstatus);// 演示 foreach (批量查询)List<UserDO>selectUsersByIds(@Param("ids")List<Long>ids);}- XML文件:包含sql语句,映射关系
- Mapper 接口的方法名必须与 XML 中的
id一一对应。 - 查询方向:数据库 → Java对象
<resultMap>标签:定义数据库查询结果字段与 DO 对象属性之间的映射关系,用于将查询结果封装为Java 对象
- 写入方向:Java对象 → 数据库
- xml文件里#{example},是从对应的方法参数里获得值
- Mapper 接口的方法名必须与 XML 中的
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">//mapper标签的namepath指向改xml对应DAO层(mapper层)<mappernamespace="com.example.mapper.UserMapper"><resultMapid="UserResultMap"type="com.example.entity.UserDO"><idproperty="id"column="id"/><resultproperty="userName"column="user_name"/><resultproperty="userEmail"column="user_email"/><resultproperty="status"column="status"/></resultMap>//sql关键字的标签id和DAO对象的方法名一一对应 //resultMao属性的值决定采用哪个映射方式<selectid="selectUsers"resultMap="UserResultMap">SELECT id, user_name, user_email, status FROM sys_user<where><iftest="name != null and name != ''">AND user_name LIKE CONCAT('%', #{name}, '%')</if><iftest="status != null">AND status = #{status}</if></where></select><selectid="selectUsersByIds"resultMap="UserResultMap">SELECT * FROM sys_user WHERE id IN<foreachcollection="ids"item="id"open="("separator=","close=")">#{id}</foreach></select><insertid="insertUser"useGeneratedKeys="true"keyProperty="id">INSERT INTO sys_user (user_name, user_email, status) VALUES (#{userName}, #{userEmail}, #{status})</insert></mapper>- Result:
importlombok.Data;/** * 统一后端返回结果封装类 * @param <T> 响应数据的泛型类型 */@Data// 使用 Lombok 自动生成 Getter/SetterpublicclassResult<T>{privateIntegercode;// 状态码:例如 200-成功, 500-系统异常, 401-未授权privateStringmsg;// 提示信息:描述本次请求的状态privateTdata;// 具体业务数据:可以是对象、列表、或 null// 私有化构造器,强制通过静态方法创建对象(符合工厂模式设计思想)privateResult(){}/** * 成功响应 - 带数据 */publicstatic<T>Result<T>success(Tdata){Result<T>result=newResult<>();result.code=200;result.msg="success";result.data=data;returnresult;}/** * 成功响应 - 不带数据 */publicstatic<T>Result<T>success(){returnsuccess(null);}/** * 失败响应 - 自定义错误信息 */publicstatic<T>Result<T>error(Stringmsg){Result<T>result=newResult<>();result.code=500;result.msg=msg;returnresult;}/** * 失败响应 - 自定义状态码和错误信息 */publicstatic<T>Result<T>error(Integercode,Stringmsg){Result<T>result=newResult<>();result.code=code;result.msg=msg;returnresult;}}- DTO
// 接收前端查询条件的传输对象publicclassUserQueryDTO{privateStringname;privateIntegerstatus;privateList<Long>ids;// Getters/Setters...}- Service实现类:
@ServicepublicclassUserServiceImplimplementsUserService{@AutowiredprivateUserMapperuserMapper;@Override@Transactional// 保证操作的原子性publicLongregisterUser(UserDOuser){userMapper.insertUser(user);returnuser.getId();// 返回插入后的主键}@OverridepublicList<UserDO>findUsers(UserQueryDTOquery){// 如果传入了具体 ID 列表,优先走批量查询,否则走动态搜索if(query.getIds()!=null&&!query.getIds().isEmpty()){returnuserMapper.selectUsersByIds(query.getIds());}returnuserMapper.selectUsers(query);}}- Controller层:
@RestController@RequestMapping("/api/users")publicclassUserController{@AutowiredprivateUserServiceuserService;@PostMapping("/search")publicResult<List<UserDO>>search(@RequestBodyUserQueryDTOquery){List<UserDO>list=userService.findUsers(query);returnResult.success(list);}@PostMapping("/save")publicResult<Long>save(@RequestBodyUserDOuser){Longid=userService.registerUser(user);returnResult.success(id);}}整体链路
标准调用流程:
前端 → Controller → DTO → Service业务处理 → Mapper接口 → XML/SQL → 数据库
↓
DO / VO