Spring MVC提供了以下几种途径输出模型数据:
1)ModelAndView:处理方法返回值类型为ModelAndView时,方法体即可通过该对象添加模型数据;
2)Map及Model:处理方法入参为org.springframework.ui.Model、org.springframework.ui.ModelMap或java.util.Map时,处理方法返回时,Map中的数据会自动被添加到模型中;
3)@SessionAttributes:将模型中的某个属性暂存到HttpSeession中,以便多个请求之间可以共享这个属性;
4)@ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中。
处理模型数据之ModelAndView
用于 获取当前时间(采用ModelAndView)
- 对象被放置在Request对象中
- 设置转向地址
- 将底层获取的数据进行存储(或者封装)
最后将数据传递给View
• 控制器处理方法的返回值如果为 ModelAndView, 则其既 包含视图信息,也包含模型数据信息。
•SpringMVC 会把 ModelAndView 的 model 中数据放入到request 域对象中。
• 添加模型数据:
MoelAndView addObject(String attributeName, Object attributeValue)
ModelAndView addAllObject(Map modelMap)
• 设置视图:示例:
void setView(View view)
void setViewName(String viewName)
首先ModelAndView 分为两部分:model和view。model负责的是从后面接收回来的参数,view就是视图就是指定的jsp页面。例如:ModelAndView mv = new ModelAndView(“test”); 所以当return mv的时候,其中view就是test.jsp页面,代码如下
ModelAndView mv = new ModelAndView("test");//文件名(例如JSP: test.jsp)
mv.addObject("username", "wang"); //"hellow"为传到jsp的数据,用aa取
例子如下:
<form action="springmvc/TestModelAndView" method="post">
用户名<input type="text" name="username"/><br/>
<input type="submit" value="提交">
</form>
@RequestMapping("/TestModelAndView")
private static final String SUCCESS = "success";
public ModelAndView TestModelAndView(@RequestParam("username") String username){
ModelAndView mv=new ModelAndView(SUCCESS);
mv.addObject("username",username);
return mv;
}
JSP页面展示:${username}
处理模型数据之Map
<a href="springmvc/TestMap">TestMap</a><br/>
private static final String SUCCESS = "success";
@RequestMapping("/TestMap")
public String TestMap(Map<String,Object> map){
map.put("city", Arrays.asList("Dog","Cat","bird"));
return SUCCESS;
}
展示页面:${city}
处理模型数据之SessionAttributes
作用:
因为对象都是放入request对象中,现在希望将Model中属性名为name的属性放到Session属性列表中,以便这个属性可以跨请求访问,那么就需要@SessionAttributes注解了
注意:@SessionAttributes这个注解只能放到类的上面
SessionAttributes除了可以通过value值来指定放入Session里的内容外,还可以使用types属性值来指定
注意:SessionAttributes只能修饰类,不能修饰方法
注意:@SessionAttributes注解只能在类(class)上面,不能在方法上面!!!
• 若希望在多个请求之间共用某个模型属性数据,则可以在控制器类(@Controller)上标注一个 @SessionAttributes, Spring MVC 将在模型中对应的属性暂存到 HttpSession 中。
• @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(实际上使用的是 value 属性值),还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(实际上使用的是 types 属性值):
– @SessionAttributes(types=User.class) 会将隐含模型中所有类型 为 User.class 的属性添加到会话中。
– @SessionAttributes(value={“user1”, “user2”})
– @SessionAttributes(types={User.class, Dept.class})
– @SessionAttributes(value={“user1”, “user2”}, types={Dept.class})
@Controller
@SessionAttributes(value={"user"},types={String.class})
@RequestMapping("/springmvc")
public class SpringMVCTest {
private static final String SUCCESS = "success";
@RequestMapping("/TestSessionAttributs")
public String TestSessionAttributs(Map<String,Object> map){
User user=new User("wang","123",50);
map.put("user", user);
map.put("pass", "123456");
return SUCCESS;
}
}
展示页面:
requestScope用户名${requestScope.user.username} <br>
requestScope密码${requestScope.pass} <br>
SessionScope用户名${sessionScope.user} <br>
SessionScope密码${sessionScope.pass} <br>
@SessionAttributes引发的异常:
错误信息:org.springframework.web.HttpSessionRequiredException: Session attribute 'user' required - not found in session
• 如果在处理类定义处标注了@SessionAttributes(“xxx”),则 尝试从会话中获取该属性,并将其赋给该入参,然后再用 请求消息填充该入参对象。如果在会话中找不到对应的属 性,则抛出 HttpSessionRequiredException 异常
Map及Model
• Spring MVC 在内部使用了一个 org.springframework.ui.Model 接口存 储模型数据
• SpringMVC 会把 Model 的数据放入到 ModelAndView 的 model 中。
• 具体步骤
– Spring MVC 在调用方法前会创建一个隐 含的模型对象作为模型数据的存储容器。
– 如果方法的入参为 Map 或 Model 类 型,Spring MVC 会将隐含模型的引用传 递给这些入参。在方法体内,开发者可以 通过这个入参对象访问到模型中的所有数 据,也可以向模型中添加新的属性数据
————————————————
使用示例:
在TestModelData.java类中追加方法:
1 @RequestMapping("/testMap")
2 public String testMap(Map<String, Object> map) {
3 map.put("mapTestKey", "mapTestValue");
4 return SUCCESS;
5 }
修改/WEB-INF/views/success.jsp页面,中
测试地址:http://localhost:8080/SpringMVC_02/testMap
返回页面打印信息:
SUCCESS PAGE
current time:
testMap mapTestKey:mapTestValue
查看此时入参Map实际什么类型,修改TestModelData.java代码:
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map) {
map.put("mapTestKey", "mapTestValue");
System.out.println(map);
System.out.println(map.getClass());
return SUCCESS;
}
打印结果:
{mapTestKey=mapTestValue}
class org.springframework.validation.support.BindingAwareModelMap
从打印结果发现,实际上入参Map是BildingAwareModelMap
public class BindingAwareModelMap extends ExtendedModelMap
public class ExtendedModelMap extends ModelMap implements Model
由于BildingAwareModelMap继承了ExtendedModelMap,而ExtendedModelMap又继承了ModeMap和实现了Model接口,因此,这里Map入参可以替换为ModelMap和Model。
调试:设置断点在“ map.put("mapTestKey", "mapTestValue");”行处
从调试跟踪发现,入参map最终被解析的类是MapMethodProcessor.java
MapMethodProcessor.java
1 /*
2 * Copyright 2002-2017 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.springframework.web.method.annotation;
18
19 import java.util.Map;
20
21 import org.springframework.core.MethodParameter;
22 import org.springframework.lang.Nullable;
23 import org.springframework.util.Assert;
24 import org.springframework.web.bind.support.WebDataBinderFactory;
25 import org.springframework.web.context.request.NativeWebRequest;
26 import org.springframework.web.method.support.HandlerMethodArgumentResolver;
27 import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
28 import org.springframework.web.method.support.ModelAndViewContainer;
29
30 /**
31 * Resolves {@link Map} method arguments and handles {@link Map} return values.
32 *
33 * <p>A Map return value can be interpreted in more than one ways depending
34 * on the presence of annotations like {@code @ModelAttribute} or
35 * {@code @ResponseBody}. Therefore this handler should be configured after
36 * the handlers that support these annotations.
37 *
38 * @author Rossen Stoyanchev
39 * @since 3.1
40 */
41 public class MapMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
42
43 @Override
44 public boolean supportsParameter(MethodParameter parameter) {
45 return Map.class.isAssignableFrom(parameter.getParameterType());
46 }
47
48 @Override
49 @Nullable
50 public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
51 NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
52
53 Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure");
54 return mavContainer.getModel();
55 }
56
57 @Override
58 public boolean supportsReturnType(MethodParameter returnType) {
59 return Map.class.isAssignableFrom(returnType.getParameterType());
60 }
61
62 @Override
63 @SuppressWarnings({ "unchecked", "rawtypes" })
64 public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
65 ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
66
67 if (returnValue instanceof Map){
68 mavContainer.addAllAttributes((Map) returnValue);
69 }
70 else if (returnValue != null) {
71 // should not happen
72 throw new UnsupportedOperationException("Unexpected return type: " +
73 returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
74 }
75 }
76
77 }
当页面返回时,该入参会被加载到Request请求域。
3)@SessionAttributes:将模型中的某个属性暂存到HttpSeession中,以便多个请求之间可以共享这个属性;
@SessionAttributes
1)若希望在多个请求之间共享某个模型属性数据,则可以在控制器类上标注@SessionAttributes,Spring MVC将在模型中对应的属性暂存到HttpSession中。
测试1:
在TestModelData.java中添加方法testSessionAttribute:
1 @RequestMapping("/testSessionAttribute")
2 public String testSessionAttribute(Map<String, Object> map) {
3 Account account = new Account("user1", "pwd123", "2018-01-07", "127.0.0.1");
4 map.put("account", account);
5
6 System.out.println("testSessionAttribute:"+map);
7
8 return SUCCESS;
9 }
<a href="testSessionAttribute">test SessionAttribute</a>
修改/WEB-INF/views/success.jsp,添加HTML脚本:
SUCCESS PAGE<br>
testSessionAttribute request:${requestScope.account.username }<br>
testSessionAttribute session:${sessionScope.account.username }<br>
此时访问index.jsp,并点击链接后条状到success.jsp也页面显示信息如下:
测试2:
此时默认情况下,并没有把account实体存放到HttpSession中,如何才能实现呢?-------修改TestModelData.java,在TestModelData类上添加注解@SessionAttributes:
1 @SessionAttributes(value = { "account" })
2 @Controller
3 public class TestModelData {
4 private final String SUCCESS = "success";
5
6 @RequestMapping("/testSessionAttribute")
7 public String testSessionAttribute(Map<String, Object> map) {
8 Account account = new Account("user1", "pwd123", "2018-01-07", "127.0.0.1");
9 map.put("account", account);
10
11 System.out.println("testSessionAttribute:" + map);
12
13 return SUCCESS;
14 }
15 }
此时重新测试,跳转到success.jsp页面时,显示结果如下:
说明已经把account实体对象存放到map的同时,也存放到了HttpSession中。
2)@SessionAttributes除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中。
测试3:
上边是通过指定属性名称的方式将account对象存放到HttpSession中的,实际上我们也可以通过指定对象类型实现把某一类对象存放到HttpSession。
修改TestModelData.java
1 @SessionAttributes(value = { "my_value_key" }, types = { Account.class, Integer.class })
2 @Controller
3 public class TestModelData {
4 private final String SUCCESS = "success";
5
6 @RequestMapping("/testSessionAttribute")
7 public String testSessionAttribute(Map<String, Object> map) {
8 Account account = new Account("user1", "pwd123", "2018-01-07", "127.0.0.1");
9 map.put("account", account);
10 map.put("my_value_key", "my_value");
11 Integer age = 30;
12 map.put("age", age);
13 Float onlineHours = 129.88f;
14 map.put("onlineHours", onlineHours);
15
16 System.out.println("testSessionAttribute:" + map);
17
18 return SUCCESS;
19 }
20 }
修改/WEB-INF/views/success.jsp页面:
1 SUCCESS PAGE<br>
2 testSessionAttribute request account.username:${requestScope.account.username }<br>
3 testSessionAttribute session account.username:${sessionScope.account.username }<br>
4 <br>
5 testSessionAttribute request my_value_key:${requestScope.my_value_key }<br>
6 testSessionAttribute session my_value_key:${sessionScope.my_value_key }<br>
7 <br>
8 testSessionAttribute request age:${requestScope.age }<br>
9 testSessionAttribute session age:${sessionScope.age }<br>
10 <br>
11 testSessionAttribute request age:${requestScope.onlineHours }<br>
12 testSessionAttribute session age:${sessionScope.onlineHours }<br>
此时访问链接地址,跳转到success.jsp页面后,显示结果:
4)@ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中。
用法示例:
Account.java
1 package com.dx.springlearn.entities;
2
3 public class Account {
4 public Integer id;
5 private String username;
6 private String password;
7 private String registerDate;
8 private String registerIP;
9
10 public Account() {
11 }
12
13 public Account(Integer id, String username, String password, String registerDate, String registerIP) {
14 super();
15 this.id = id;
16 this.username = username;
17 this.password = password;
18 this.registerDate = registerDate;
19 this.registerIP = registerIP;
20 }
21
22 public Account(String username, String password, String registerDate, String registerIP) {
23 super();
24 this.username = username;
25 this.password = password;
26 this.registerDate = registerDate;
27 this.registerIP = registerIP;
28 }
29
30 public Integer getId() {
31 return id;
32 }
33
34 public void setId(Integer id) {
35 this.id = id;
36 }
37
38 public String getUsername() {
39 return username;
40 }
41
42 public void setUsername(String username) {
43 this.username = username;
44 }
45
46 public String getPassword() {
47 return password;
48 }
49
50 public void setPassword(String password) {
51 this.password = password;
52 }
53
54 public String getRegisterDate() {
55 return registerDate;
56 }
57
58 public void setRegisterDate(String registerDate) {
59 this.registerDate = registerDate;
60 }
61
62 public String getRegisterIP() {
63 return registerIP;
64 }
65
66 public void setRegisterIP(String registerIP) {
67 this.registerIP = registerIP;
68 }
69
70 @Override
71 public String toString() {
72 return "Account [id=" + id + ", username=" + username + ", password=" + password + ", registerDate="
73 + registerDate + ", registerIP=" + registerIP + "]";
74 }
75
76
77 }
Handler类TestModelData.java
1 package com.dx.springlearn.hanlders;
2
3 import java.text.SimpleDateFormat;
4 import java.util.Date;
5 import java.util.Map;
6
7 import org.springframework.stereotype.Controller;
8 import org.springframework.web.bind.annotation.ModelAttribute;
9 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.RequestParam;
11 import org.springframework.web.servlet.ModelAndView;
12
13 import com.dx.springlearn.entities.Account;
14
15 @Controller
16 public class TestModelData {
17 private final String SUCCESS = "success";
18
19 @ModelAttribute
20 public void getAccount(@RequestParam(name = "id", required = false) Integer id, Map<String, Object> map) {
21 if (id != null) {
22 System.out.println("read account(id=" + id + ") from db");
23 Account account = new Account(1, "tommy", "123456", "2018-01-20 21:56:09", "127.0.0.1");
24 map.put("account", account);
25 } else {
26 System.out.println("the acount id is null");
27 }
28 }
29
30 @RequestMapping("/testModelAttribute")
31 public ModelAndView testModelAttribute(Account account) {
32 System.out.println("accept account:" + account);
33 String viewName = SUCCESS;
34 ModelAndView modelAndView = new ModelAndView(viewName);
35 modelAndView.addObject("currentTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
36
37 return modelAndView;
38 }
39 }
测试表单页面:
<form id="form_testModelAttribute" action="testModelAttribute"
method="POST">
<input name="id" type="hidden" value="1"/>
username:<input name="username" type="text" value="tommy" /><br>
<!-- password:<input name="password" type="password" /><br> -->
register date:<input name="registerDate" type="text" value="2018-01-20 21:56:09" /><br>
register ip:<input name="registerIP" type="text" value="127.0.0.1"/><br>
<input type="submit" value="Submit"/>
</form>
除了handler目标方法参数第一个参数名称与存放到map中的对象名称一致外,也可以使用@ModelAttribute标注handler目标方法参数:
package com.dx.springlearn.hanlders;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.dx.springlearn.entities.Account;
@Controller
public class TestModelData {
private final String SUCCESS = "success";
@ModelAttribute
public void getAccount(@RequestParam(name = "id", required = false) Integer id, Map<String, Object> map) {
if (id != null) {
System.out.println("read account(id=" + id + ") from db");
Account account = new Account(1, "tommy", "123456", "2018-01-20 21:56:09", "127.0.0.1");
map.put("testabc", account);
} else {
System.out.println("the acount id is null");
}
}
@RequestMapping("/testModelAttribute")
public ModelAndView testModelAttribute(@ModelAttribute("testabc") Account account) {
System.out.println("accept account:" + account);
String viewName = SUCCESS;
ModelAndView modelAndView = new ModelAndView(viewName);
modelAndView.addObject("currentTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
return modelAndView;
}
}
运行流程:
1)运行有@ModelAttribute注解标注的方法:从数据库中取出对象,把对象放入到Map中,键值为:user;
2)SpringMVC从Map中取出User对象,并把表单的请求参数赋值给该User对象的对应属性;
3)SpringMVC把上述对象传入目标方法的参数(参数名称必须与Map中的键值一致)。
注意:在@ModelAttribute修饰的方法中,放入Map是的键类型要与目标方法入参类型一直,而且Map是的键名称要与目标方法入参的参数名一致。
@ModelAttribute 源代码分析流程
1、调用@ModelAttribute注解修饰的方法,实际上把@ModelAttribute方法中Map中的数据放在了implicitModel中。
2、解析请求处理器的目标参数,实际上该目标参数来自WebDataBinder对象的target属性:
— 创建WebDataBinder对象:
(1)、确定objectName属性:若传入的attrName属性值为"",则objectName为类名第一个字母小写。注意:attrName,若目标方法中POJO属性使用了@ModelAttribute来修饰,则attrName值即为@ModelAttribute的value属性值!
(2)、确定target属性:在implicitModel中查找attrName对应的属性值,若存在则继续;若不存在,则验证当前Handler是否使用了@SessionAttributes进行修饰,若使用了,则尝试从Session中获取attrName所对应的属性值,若session中没有对应的属性值,则抛出异常。若Handler没有使用@SessionAttributes进行修饰,或@SessionAttributes中没有使用value值指定的键(key),和attrName相匹配,则通过反射创建POJO对象。
— SpringMVC把表单的请求参数赋值给了 WebDataBinder 的 target 对应的属性。
— SpringMVC会把 WebDataBinder 的 attrName 和 target 给到 implicitModel。近而传到 request 域对象中。
— 把 WebDataBinder 的 target 作为参数传递给目标方法的入参。
Spring MVC 确定目标方法POJO类型入参的过程
1、确定一个键key。若目标方法的POJO类型的参数没有使用@ModelAttribute作为修饰,则key为POJO类名的第一个字母的小写;若使用了@ModelAttribute来进行修饰,则key为@ModelAttribute注解的value属性值。
2、在implicitModel中查找key对应的对象,若存在,则作为入参传入。若在@ModelAttribute标记的方法中在Map中保存过,且key 和 值确定的key一致,则会获取到。
3、若implicitModel中不存在key对应的对象,则检查当前Handler 是否使用@SessionAttributes注解修饰,若使用了该注解,且@SessionAttributes注解的value属性值中包含了key,则会从HTTPSession中来获取key所对应的value值;若存在则直接传入到目标方法的入参中;若不存在则抛出异常。
4、若Handler没有标识@SessionAttributes注解或@SessionAttributes注解的value值中不包含key,则会通过反射来创建POJO类型的参数,传入为目标方法的参数。
5、Spring MVC会把key 和POJO类型的对象保存到implicitModel中,进而会保存到request中。
示例
index.jsp
<%--
Created by IntelliJ IDEA.
User: 23369
Date: 2019/3/24
Time: 18:29
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=gbk" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="TestModelAttribute/testUserInfo" method="post">
<input type="text" name="username" placeholder="请输入用户名">
<br>
<input type="password" name="userpass" placeholder="请输入密码">
<br>
<input type="text" name="useremail" placeholder="请输入邮箱">
<br>
<input type="text" name="userage" placeholder="请输入年龄">
<br>
<input type="text" name="address.procity" placeholder="请输入省份">
<br>
<input type="text" name="address.city" placeholder="请输入城市">
<br>
<input type="submit" value="提交">
</form>
</body>
</html>
success.jsp
<%--
Created by IntelliJ IDEA.
User: 23369
Date: 2019/3/24
Time: 18:33
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>success</h1>
request 用户信息:${requestScope.userinfo}
<br>
session 用户信息:${sessionScope.userinfo}
<br>
<br>
request 用户信息修改:${requestScope.userinfoModel}
<br>
session 用户信息修改:${sessionScope.userinfoModel}
<br>
</body>
</html>
TestModelAttribute.class
package com.helloworld;
import com.user.Address;
import com.user.UserInfo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@SessionAttributes(value = {"userinfo"}, types = String.class)
@Controller
@RequestMapping("TestModelAttribute")
public class TestModelAttribute {
private String success = "success";
@ModelAttribute
public void getUserInfo(@RequestParam(value = "userpass", required = false) Integer id, Map<Object, Object> map){
System.out.println(id);
UserInfo userInfo = new UserInfo("Hern","123","123456","35",new Address("aaa","bbb"));
map.put("userinfoModel",userInfo);
}
@RequestMapping(value = "testUserInfo", method = RequestMethod.POST)
public String testUserInfo(UserInfo userInfo,Map<Object, Object> map){
System.out.println(userInfo);
map.put("userinfo",userInfo);
return success;
}
/*
这种方法可以避免因为POJO类型对象造成的无法传参问题,可以不使用,因为SpringMVC能够自动映射
@RequestMapping(value = "testUserInfo", method = RequestMethod.POST)
public String testUserInfo(@ModelAttribute("userinfo") UserInfo userInfo,Map<Object, Object> map){
System.out.println(userInfo);
map.put("userinfo",userInfo);
return success;
}
*/
}
面试相关:
2021年JAVA 精心整理的常见面试题-附详细答案【持续更新~~】 | https://mikejun.blog.csdn.net/article/details/114488339 |
精心整理的计算机各类别的电子书籍【超全】 | https://mikejun.blog.csdn.net/article/details/115442555 |
2021年- 精心整理的 SpringMVC 常见面试题-【附详细答案】 | https://mikejun.blog.csdn.net/article/details/114992529 |
2021年- 精心整理的 SpringBoot 常见面试题-【附详细答案】 | https://mikejun.blog.csdn.net/article/details/115682106 |
2021年SpringCloud 精选大厂面试题-【附详细答案】 | https://mikejun.blog.csdn.net/article/details/116103358 |
2021年JAVA 面试题之--数据结构篇【附详细答案】 | https://mikejun.blog.csdn.net/article/details/114647742 |
Java 多线程、多进程、并发编程面试总结 (2021年) | https://mikejun.blog.csdn.net/article/details/115830507 |
三天刷完《剑指OFFER编程题》--Java版本实现(第一天) | https://mikejun.blog.csdn.net/article/details/106996017 |
三天刷完《剑指OFFER编程题》--Java版本实现(第二天) | https://mikejun.blog.csdn.net/article/details/108098502 |
三天刷完《剑指OFFER编程题》--Java版本实现(第三天) | https://mikejun.blog.csdn.net/article/details/108253489 |
项目推荐:
Java微服务实战296集大型视频-谷粒商城【附代码和课件】
Java开发微服务畅购商城实战【全357集大项目】-附代码和课件