代码地址:https://gitee.com/it_feiyue/feiyue-mvc.git
1、创建maven工程(此过程比较简单,不详细介绍)
图示为项目结构:
2、创建控制层、业务层代码(Controller、Service自定义注解)、准备springmvc核心配置文件
2-1、创建自定义注解
@Controller
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {
String value() default "";
}
@Service
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
String value();
}
@RequestMapping
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
String value() default "";
}
@AutoWired
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoWired {
String value();
}
2-2、准备控制层代码、业务层代码
控制层:
@Controller
public class UserController {
@AutoWired("userService")
UserService userService;
//定义方法
@RequestMapping("/findUser")
public String findUser(){
//调用服务层
userService.findUser();
return "success.jsp";
}
}
业务层:
接口:
public interface UserService {
String findUser();
}
实现类:
@Service(value="userService")
public class UserServiceImpl implements UserService {
@Override
public String findUser() {
System.out.println("====调用UserServiceImpl === findUser===");
return null;
}
}
2-3、准备springmvc核心配置文件
web.xml配置前端控制器:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>com.springmvc.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--Web服务器一旦启动,Servlet就会实例化创建对象,然后初始化(预备创建对象)-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
springmvc.xml配置要扫描的包:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- 配置创建容器时要扫描的包-->
<component-scan base-package="com.feiyue.controller,com.feiyue.service"></component-scan>
</beans>
3、准备前端控制器,创建一个servlet,同时在web.xml中声明该前端控制器
创建DispatcherServlet及前端控制器:
public class DispatcherServlet extends HttpServlet {}
4、创建springmvc容器,通过dom4j解析springmvc的配置文件
/**
* @author FEIYUE
* @description springmvc容器
* @date 2020/10/22
*/
public class WebApplicationContext {}
public class XmlPaser {
public static String getBasePackage(String xml){
try {
SAXReader saxReader = new SAXReader();
InputStream inputStream = XmlPaser.class.getClassLoader().getResourceAsStream(xml);
//xml文档对象
Document document = saxReader.read(inputStream);
Element rootElement = document.getRootElement();
Element componentScan = rootElement.element("component-scan");
Attribute attribute = componentScan.attribute("base-package");
String basePackage = attribute.getText();
return basePackage;
} catch (DocumentException e) {
e.printStackTrace();
} finally {
}
return "";
}
}
5、扫描springmvc中的控制器及Service类,并实例化对象放入到容器中
/**
* 实例化容器中的bean
*/
private void executeInstance() {
try {
//包名.类名
for (String className : classNameList) {
Class<?> clazz = Class.forName(className);
if (clazz.isAnnotationPresent(Controller.class)){
//控制层bean
String beanName = clazz.getSimpleName().substring(0,1).toLowerCase()+clazz.getSimpleName().substring(1);
iocMap.put(beanName,clazz.newInstance());
}else if (clazz.isAnnotationPresent(Service.class)){
//业务层bean
Service service = clazz.getAnnotation(Service.class);
String beanName = service.value();
iocMap.put(beanName,clazz.newInstance());
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
6、实现容器中对象的注入,比如向控制层中注入服务层
/**
* 进行自动注入操作
*/
private void executeAutoWired() {
try {
//从容器中取出bean,然后判断bean中是否有属性上使用AutoWired,如果使用了该注解,就需要进行自动注入操作
for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
//获取容器中的bean
Object bean = entry.getValue();
//获取bean中的属性
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(AutoWired.class)){
//获取注解中的value值
AutoWired autoWired = field.getAnnotation(AutoWired.class);
String beanName = autoWired.value();
//从容器中获取实例
Object realBean = iocMap.get(beanName);
field.setAccessible(true);
field.set(bean,realBean);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
7、建立请求映射地址与控制器及方法之间的映射关系
/**
* 初始化请求映射关系
*/
private void initHandlerMapping() {
for (Map.Entry<String, Object> 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);
//获取注解中的值 /findUser
String url = requestMapping.value();
//建立映射地址和控制器中方法的关系
MyHandler handler = new MyHandler(url, entry.getValue(), method);
handlerList.add(handler);
}
}
}
}
}
8、接受用户请求并进行分发操作
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//进行请求分发处理
doDispatcher(req,resp);
}
/**
* 进行请求分发处理
* @param req
* @param resp
*/
private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) {
//根据用户请求查找对应的handler
MyHandler myHandler = getHandler(req);
try {
if (null == myHandler){
resp.getWriter().print("404 NOT FOUND");
}else {
//调用处理方法之前 进行参数注入
//调用目标方法
Object result = myHandler.getMethod().invoke(myHandler.getController());
if (result instanceof String){
//跳转jsp
String viewName = (String)result;
//forward:/success.jsp
if (viewName.contains(":")) {
String viewType = viewName.split(":")[0];
String viewPage = viewName.split(":")[1];
if (viewType.equals("forward")){
req.getRequestDispatcher(viewPage).forward(req,resp);
}else {
//redirect:/user.jsp
resp.sendRedirect(viewPage);
}
}else {
//默认是转发
req.getRequestDispatcher(viewName).forward(req,resp);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
9、用户请求参数处理
10、控制器方法调用以及不同返回值数据处理