你对SpringMVC了解多少呢?SpringMVC可以说得上是当前最优秀的MVC框架,采用了松散耦合可插拔组件结构,比其他MVC框架更具扩展性和灵活性;为了提高框架的扩展性和灵活性,设计了松耦合可插拔的组件。理解SpringMVC的原理,在面试或工作中都十分的重要。
SpringMVC的原理在网络上到处都可以找得到,但是写得都很概括、零散;对应阅读源码经验较少的小伙伴来说,自己去看源码被很多细节所干扰阻碍,不能够很好地抽离出springMVC原理的主线。
下面就给大家分享一下LZ整理的有关SpringMVC的学习资料,学会用代码说话!
1.1、创建Maven工程
2.1、pom依赖
4.0.0
com.zhz
simulation-springmvc
1.0-SNAPSHOT
war
simulation-springmvc Maven Webapp
http://www.example.com
UTF-8
1.7
1.7
junit
junit
4.11
test
javax.servlet
javax.servlet-api
3.1.0
provided
dom4j
dom4j
1.6.1
org.apache.commons
commons-lang3
3.5
org.projectlombok
lombok
1.18.12
com.fasterxml.jackson.core
jackson-databind
2.9.1
simulation-springmvc
maven-clean-plugin
3.1.0
maven-resources-plugin
3.0.2
maven-compiler-plugin
3.8.0
maven-surefire-plugin
2.22.1
maven-war-plugin
3.2.2
maven-install-plugin
2.5.2
maven-deploy-plugin
2.8.2
2.2、springmvc配置类
2.3、web.xml
Archetype Created Web Application
DispatcherServlet
com.zhz.springmvc.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc.xml
1
DispatcherServlet
/
实体类:User.java
package com.zhz.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author :zhz
* @date :Created in 2021/01/04
* @version: V1.0
* @slogan: 天下风云出我辈,一入代码岁月催
* @description: 实体类
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
private String password;
}
package com.zhz.controller;
import com.zhz.bean.User;
import com.zhz.service.UserService;
import com.zhz.springmvc.annotation.Autowired;
import com.zhz.springmvc.annotation.Controller;
import com.zhz.springmvc.annotation.RequestMapping;
import com.zhz.springmvc.annotation.ResponseBody;
/**
* @author :zhz
* @date :Created in 2021/01/03
* @version: V1.0
* @slogan: 天下风云出我辈,一入代码岁月催
* @description: 控制器
**/
@Controller
public class UserController {
@Autowired(value = "userService")
private UserService userService;
@RequestMapping("/listUsers")
public String listUsers(){
userService.listUsers();
return "forward:/success.jsp";
}
@RequestMapping("/getData")
@ResponseBody //返回json格式的数据
public User getData(){
//调用服务层
return userService.getUser();
}
}
package com.zhz.service;
import com.zhz.bean.User;
/**
* @author :zhz
* @date :Created in 2021/01/03
* @version: V1.0
* @slogan: 天下风云出我辈,一入代码岁月催
* @description:
**/
public interface UserService {
void listUsers();
User getUser();
}
package com.zhz.service.impl;
import com.zhz.bean.User;
import com.zhz.service.UserService;
import com.zhz.springmvc.annotation.Service;
/**
* @author :zhz
* @date :Created in 2021/01/03
* @version: V1.0
* @slogan: 天下风云出我辈,一入代码岁月催
* @description:
**/
@Service("userService")
public class UserServiceImpl implements UserService {
@Override
public void listUsers() {
System.out.println("===调用===UserServiceImpl===listUser===");
}
@Override
public User getUser() {
return new User(1,"zhz","123456");
}
}
6.1、核心annotation注解
package com.zhz.springmvc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Retention注解表示Annotation的保留策略 RetentionPolicy.Class:运行时不保留,不可以通过反射读取。
* RetentionPolicy.RUNTIME:运行是保留,可以通过反射读取。
* RetentionPolicy.SOURCE:丢弃。
*/
@Target(value = ElementType.FIELD) //作用在属性上
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Autowired {
String value();
}
package com.zhz.springmvc.annotation;
import java.lang.annotation.*;
@Target(ElementType.TYPE) // //作用在类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {
String value() default "";
}
package com.zhz.springmvc.annotation;
import java.lang.annotation.*;
@Target(ElementType.METHOD) //作用在方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
String value() default "";
}
package com.zhz.springmvc.annotation;
import java.lang.annotation.*;
/**
* @BelongsProject: SpringMvc
*/
@Target(ElementType.METHOD) //作用在方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
}
package com.zhz.springmvc.annotation;
import java.lang.annotation.*;
/**
* @Description: 自定义注解
*/
@Target(ElementType.TYPE) //作用在类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
String value();
}
6.2、context上下文(SpringMVC容器)
package com.zhz.springmvc.context;
import com.zhz.springmvc.annotation.Autowired;
import com.zhz.springmvc.annotation.Controller;
import com.zhz.springmvc.annotation.Service;
import com.zhz.springmvc.xml.XmlParse;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author :zhz
* @date :Created in 2021/01/03
* @version: V1.0
* @slogan: 天下风云出我辈,一入代码岁月催
* @description: SpringMVC容器
**/
public class WebApplicationContext {
//classpath:springmvc.xml
String contextConfigLocation;
//定义集合 用于存放 bean 的权限名|包名.类名
List classNameList = new ArrayList<>();
//创建Map集合用于扮演IOC容器: key存放bean的名字 value存放bean实例
public Map iocMap = new ConcurrentHashMap<>();
public WebApplicationContext() {
}
public WebApplicationContext(String contextConfigLocation) {
this.contextConfigLocation = contextConfigLocation;
}
/**
* 初始化Spring容器
*/
public void onRefresh() {
//1、进行解析spring mvc配置文件操作 ==》 com.zhz.controller,com.zhz.service
String basePackage = XmlParse.getBasePackage(contextConfigLocation.split(":")[1]);
//通过","来分割com.zhz.controller,com.zhz.service 获得对应的包名
String[] packs = basePackage.split(",");
//2、进行包扫描
for (String pack : packs) {
executeScanPackage(pack);
}
//3、实例化容器中的bean
executeInstance();
//4、进行自动注入操作
executeAutowired();
}
/**
* 进行包扫描
*
* @param pack
*/
private void executeScanPackage(String pack) {
//1、把com.zhz.controller====>com/zhz/controller com.zhz.service====>com/zhz/controller
URL url = this.getClass().getClassLoader().getResource("/" + pack.replaceAll("\\.", "/"));
String path = url.getFile();
//2、/com/zhz/service
File dir = new File(path);
for (File file : dir.listFiles()) {
if (file.isDirectory()) {//说明是com.zhz.service.impl层
executeScanPackage(pack + "." + file.getName());
} else {
//文件目录下文件 获取全路径 UserController.class ==> com.zhz.controller.UserController
String className = pack + "." + file.getName().replaceAll(".class", "");
classNameList.add(className);
}
}
}
/**
* 实例化容器
*/
private void executeInstance() {
try {
// com.zhz.controller.UserController com.zhz.service.impl.UserServiceImpl
for (String className : classNameList) {
Class> clazz = Class.forName(className);
if (clazz.isAnnotationPresent(Controller.class)) {
//控制层的bean,得到类的简写名称也就是UserController
String beanName = clazz.getSimpleName().substring(0, 1).toLowerCase()+clazz.getSimpleName().substring(1);//首位变为小写
iocMap.put(beanName, clazz.newInstance());
} else if (clazz.isAnnotationPresent(Service.class)) {
//Service层,主要是为了获得他的value
Service service = clazz.getAnnotation(Service.class);
String beanName = service.value();
iocMap.put(beanName, clazz.newInstance());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
/**
* 进行自动注入操作
*/
private void executeAutowired() {
try {
//从容器中取出bean,然后判断bean中是否有属性上使用Autowired,如果使用了该注解,就需要进行自动注入操作
for (Map.Entry entry : iocMap.entrySet()) {
//取出容器中的bean
Object bean = entry.getValue();
//从bean中获取属性
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
//获取注解中的value值,该值是bean的name
Autowired autowired = field.getAnnotation(Autowired.class);
String beanName = autowired.value();
;
//取消检查机制
field.setAccessible(true);
field.set(bean, iocMap.get(beanName));
}
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
6.3、映射处理(url与ccontroller之间的映射)
package com.zhz.springmvc.handler;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.lang.reflect.Method;
/**
* @author :zhz
* @date :Created in 2021/01/04
* @version: V1.0
* @slogan: 天下风云出我辈,一入代码岁月催
* @description:
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HandlerMapping {
//请求URL地址
private String url;
//控制器
private Object controller;
//控制器的方法
private Method method;
}
6.4、前端处理器
package com.zhz.springmvc.servlet;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhz.springmvc.annotation.Controller;
import com.zhz.springmvc.annotation.RequestMapping;
import com.zhz.springmvc.annotation.ResponseBody;
import com.zhz.springmvc.context.WebApplicationContext;
import com.zhz.springmvc.handler.HandlerMapping;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author :zhz
* @date :Created in 2021/01/03
* @version: V1.0
* @slogan: 天下风云出我辈,一入代码岁月催
* @description: 前端控制器
**/
public class DispatcherServlet extends HttpServlet {
//指定SpringMvc容器
private WebApplicationContext webApplicationContext;
//创建集合,用于存放映射关系、映射地址与控制器.方法,用于发送请求直接从该集合中进行匹配
List handList = new ArrayList<>();
@Override
public void init() throws ServletException {
//1、从web.xml中获得加载初始化参数contextConfigLocation的值classpath:springmvc.xml
String configLocation = this.getServletConfig().getInitParameter("contextConfigLocation");
//2、创建SpringMVC容器
webApplicationContext = new WebApplicationContext(configLocation);
//3、进行初始化操作
webApplicationContext.onRefresh();
//4、初始化请求映射关系 /findUser ===》控制器.方法
initHandlerMapping();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//进行请求分发处理
doDispatcher(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
/**
* 初始化请求映射关系(获取链接地址0
*/
private void initHandlerMapping() {
//遍历map, key存放bean的名字 value存放bean实例
for (Map.Entry entry : webApplicationContext.iocMap.entrySet()) {
//获得bean的class类型
Class> clazz = entry.getValue().getClass();
if (clazz.isAnnotationPresent(Controller.class)) {
//获取bean中所有的方法,为这些方法建立映射关系
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
//获取注解中的值
String url = requestMapping.value();
//建立映射地址,与控制器 方法
HandlerMapping handlerMapping = new HandlerMapping(url, entry.getValue(), method);
handList.add(handlerMapping);
}
}
}
}
}
/**
* 进行请求分发处理
*
* @param request
* @param response
*/
private void doDispatcher(HttpServletRequest request, HttpServletResponse response) {
try {
//根据用户的请求地址(/listUsers)查找Controller
HandlerMapping handlerMapping = getHandler(request);
if (handlerMapping == null) {
response.getWriter().print("404 NOT FOUND!
");
} else {
//调用处理方法之前 进行参数的注入
//调用目标方法---》获得方法的返回值类型
Object result = handlerMapping.getMethod().invoke(handlerMapping.getController());
if (result instanceof String){
//跳转到JSP中
String viewName = (String)result;
//forward:/success.jsp重定向
if (viewName.contains(":")){
String viewType=viewName.split(":")[0];//也就是forward或者redirect
String viewPage=viewName.split(":")[1];//跳转的页面
if (viewType.equals("forward")){//请求转发
request.getRequestDispatcher(viewPage).forward(request,response);
}else{//重定向
response.sendRedirect(viewPage);
}
}else{
//默认请求转发
request.getRequestDispatcher(viewName).forward(request,response);
}
}else{
//返回JSON格式数据
Method method=handlerMapping.getMethod();
if (method.isAnnotationPresent(ResponseBody.class)){
//将返回值转换成 json格式数据
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(result);
response.setContentType("text/html;charset=utf-8");
PrintWriter writer= response.getWriter();
writer.print(json);
writer.flush();
writer.close();
}
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ServletException e) {
e.printStackTrace();
}
}
/**
* 根据用户请求查找对应的Handler======>获取请求对应的handler(也就是从handList中取出)
*
* @param request
* @return
*/
private HandlerMapping getHandler(HttpServletRequest request) {
String requestURI = request.getRequestURI();
for (HandlerMapping handlerMapping : handList) {
//从容器的Handle取出URL 和 用户的请求地址进行匹配,找到满足条件的Handler(controller)
if (handlerMapping.getUrl().equals(requestURI)) {
return handlerMapping;
}
}
return null;
}
}
6.5、解析XML
package com.zhz.springmvc.xml;
import lombok.val;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.io.InputStream;
/**
* @author :zhz
* @date :Created in 2021/01/04
* @version: V1.0
* @slogan: 天下风云出我辈,一入代码岁月催
* @description: 解析spring mvc.xml
**/
public class XmlParse {
public static String getBasePackage(String xml){
try {
SAXReader saxReader=new SAXReader();
// 通过reader对象的read方法加载spring mvc.xml文件,获取docuemnt对象。
InputStream inputStream = XmlParse.class.getClassLoader().getResourceAsStream(xml);
Document document = saxReader.read(inputStream);
// 通过document对象获取根节点beans
Element rootElement = document.getRootElement();
// 通过element对象的返回给定本地名称和任何名称空间的第一个元素
Element componentScan = rootElement.element("component-scan");
//返回componentScan的参数
Attribute attribute = componentScan.attribute("base-package");
//返回base-package的值
String basePackage = attribute.getText();
return basePackage;
} catch (DocumentException e) {
e.printStackTrace();
}
return "";
}
}
7.1、index.jsp
Hello World!
7.2、succes.jsp
Hello World!
跳转至success.jsp页面
这篇关于手撕springMVC的文章就先更到这里了,感谢你看到这里,文章有什么不足还请指正,觉得文章对你有帮助的话记得给我点个赞,SpringMVC其实并不算是一个很难的知识点,用点心多看就很简单
每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!
原文链接:
https://www.tuicool.com/articles/ZRN7raM