代码实现SpringMvc
偶然看到一篇100多行实现SpringMvc的博客,阅读后整理加实现出来。大家共勉!(纸上得来终觉浅,绝知此事要躬行。)
实现Spring的部分。
- Bean工厂,统一创建Bean;
- IOC,实现Bean的依赖注入;
- DispatchServlet,SpringMVC的路径映射。
代码解析如下:
1、首先创建Servelt,继承HttpServlet。覆盖init/doGet/doPost方法。
@Override
public void init() throws ServletException {
try {
// 初始化配置文件
initConfig(super.getServletConfig().getInitParameter(CONFIG_NAME));
// 扫描类
doScanPackage(configProperties.getProperty("packageScan"));
// 加载类
initBeanInitializing();
// 依赖注入
initBeanAutowired();
// 路径映射
initServletDispatch();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("====>beanFactory:\n"+beanFactory);
System.out.println("====>requestMap:\n"+requestMap);
} @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{
doDispatch(req,resp);
}
2、配置web.xml
<servlet>
<servlet-name>cwDispatchServlet</servlet-name>
<servlet-class>com.cw.servlets.CWDispatchServlet</servlet-class>
<init-param>
<param-name>dispatchConfig</param-name>
<param-value>config.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>cwDispatchServlet</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
2.1、配置文件config.properties在根目录,如下
# 设置配置文件
packageScan=com.cw.demo
3、定义支持的注入,如
Autowired
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Inherited
public @interface CWAutowired {
String value() default "";
}
Controller
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface CWController {
String value() default "";
}
RequestMapping
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@Inherited
public @interface CWRequestMapping {
String value() default "";
}
Service
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface CWService {
String value() default "";
}
4、在Servlet的init方法中,依次实现
4.1、加载配置文件
private void initConfig(String configName){
InputStream inputStream = null;
try {
System.out.println("------->configName:"+configName);
inputStream = this.getClass().getClassLoader().getResourceAsStream(configName);
configProperties.load(inputStream);
} catch (Exception e) {
e.printStackTrace();
}finally {
if(null != inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.1、扫描所有Java类
/**
* 扫描类
* @Title: doScanPackage
* @param packagePath
* @return void
*/
private void doScanPackage(String packagePath) {
System.out.println("path:"+packagePath.replaceAll("\\.", "/"));
URL url = this.getClass().getClassLoader().getResource("/"+packagePath.replaceAll("\\.", "/"));
File file = new File(url.getFile());
for(File sub:file.listFiles()) {
if(sub.isDirectory()) {
doScanPackage(packagePath+"."+sub.getName());
}else {
String clsName = packagePath+"."+sub.getName().replace(".class","");
this.clsList.add(clsName);
}
}
}
4.3、初始化类
private void initBeanInitializing() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
for(String clsName:clsList) {
Class cls = Class.forName(clsName);
if(cls.isAnnotationPresent(CWController.class)) {
String name = cls.getSimpleName();
beanFactory.put(lowerFirstChar(name) , cls.newInstance());
}else if(cls.isAnnotationPresent(CWService.class)) {
CWService service = (CWService) cls.getAnnotation(CWService.class);
String defaultName = service.value();
if(!"".equals(defaultName)) {
beanFactory.put(defaultName, cls.newInstance());
}else {
Class[] interfaces = cls.getInterfaces();
Object instance = cls.newInstance();
for(Class inter:interfaces) {
beanFactory.put(lowerFirstChar(inter.getSimpleName()), instance);
}
}
}else if(cls.isAnnotationPresent(CWComponent.class)){
String name = cls.getName();
beanFactory.put(lowerFirstChar(name), cls.newInstance());
}
}
}
4.4、完成类的依赖注入
private void initBeanAutowired() throws IllegalArgumentException, IllegalAccessException {
for(Map.Entry<String, Object> entry:beanFactory.entrySet()) {
Object bean = entry.getValue();
Field[] fields = bean.getClass().getDeclaredFields();
if(null == fields || fields.length ==0 ) {
continue;
}
for(Field field:fields) {
if(field.isAnnotationPresent(CWAutowired.class)) {
String fieldTypeName = field.getType().getSimpleName();
field.setAccessible(true);
field.set(bean, beanFactory.get(this.lowerFirstChar(fieldTypeName)));
}
}
}
}
4.5、完成request的路径映射
private void initServletDispatch() {
for(Map.Entry<String, Object> entry:beanFactory.entrySet()) {
Object bean = entry.getValue();
System.out.println(entry.getKey()+":"+entry.getValue());
if(!bean.getClass().isAnnotationPresent(CWController.class)) {
continue;
}
// 基本路径
String basePath = "";
if(bean.getClass().isAnnotationPresent(CWRequestMapping.class)) {
basePath = ((CWRequestMapping)bean.getClass().getAnnotation(CWRequestMapping.class)).value();
}
System.out.println("=========>basePath:"+basePath);
// 方法路径
Method[] methods = bean.getClass().getMethods();
for(Method method:methods) {
if(method.isAnnotationPresent(CWRequestMapping.class)) {
String path = ((CWRequestMapping)method.getAnnotation(CWRequestMapping.class)).value();
requestMap.put(("/"+basePath +"/"+path).replaceAll("/+", "/"), method);
}
}
}
}
5、处理页面请求
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws UnsupportedEncodingException, IOException {
String url = req.getRequestURI();
String contextPath = req.getContextPath();
url = url.replace(contextPath, "").replaceAll("/+", "/");
System.out.println("=========>request url:"+url);
Method method = this.requestMap.get(url);
if(null == method) {
resp.getOutputStream().write("404 not found!".getBytes("UTF-8"));
return;
}
String beanName = this.lowerFirstChar(method.getDeclaringClass().getSimpleName());
try {
method.invoke(beanFactory.get(beanName), req,resp);
}catch (Exception e) {
e.printStackTrace();
resp.getOutputStream().write("404 not found!".getBytes("UTF-8"));
}
}
6、添加测试类了
HelloWorldAction.java
@CWController
@CWRequestMapping("/h")
public class HelloWorldAction {
@CWAutowired
private IUserService userService; @CWRequestMapping("/hello.htm")
public void hello(HttpServletRequest request,HttpServletResponse response) {
try {
System.out.println(userService.getUserNameById(1L));
response.getWriter().write("hello World!");
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
}
}
}
IUserService.java
public interface IUserService { public String getUserNameById(Long id);
}
UserServiceImpl.java
@CWService
public class UserServiceImpl implements IUserService { @Override
public String getUserNameById(Long id) {
return "master";
} }
7、tomcat启动,大功告成
http:127.0.0.1:8080/h/hello.htm
总结:
1、看别人的代码,很简单,自己实现就发现很多坑。关键还是要自己实践。实践!实践!实践!
备注:
1、参考来源
https://www.toutiao.com/i6636629045259796995/
2、工程源码
https://pan.baidu.com/s/1F0el_nwDJ99-AYueeH0esw
代码实现SpringMvc的更多相关文章
- 基于java代码的springmvc配置
在我的印象中,开发一个web项目首选当然是springmvc,而配置springmvc无非就是web.xml里配置其核心控制器DispatcherServlet.然后把所有的请求都交给它处理,再配个视 ...
- 基于java代码的Spring-mvc框架配置
Spring 版本 4.3.2 maven项目 1.首先上项目目录图,主要用到的配置文件,略去css和js的文件 引包: 2.主要代码: (1)NetpageWebAppInitializer类 ...
- 编写手机端自适应页面案例,springMVC代码,SpringMVC上传代码,去掉input框中原有的样式,使ios按钮没有圆角,css中的border-radius类似
1.编写的页面 <%@ page language="java" contentType="text/html; charset=UTF-8" page ...
- SpringMVC(一) 简单代码编写,注解,重定向与转发
SpringMVC是什么 SpringMVC是目前最好的实现MVC设计模式的框架,是Spring框架的一个分支产品,以SpringIOC容器为基础,并利用容器的特性来简化它的配置.SpringMVC相 ...
- 零配置文件搭建SpringMVC实践纪录
本篇记录使用纯java代码搭建SpringMVC工程的实践,只是一个demo.再开始之前先热身下,给出SpringMVC调用流程图,讲解的是一个http request请求到达SpringMVC框架后 ...
- 3.SpringMVC修改配置文件路径和给界面传递数据
1.修改配置文件路径 达到 配置多文件的目的 web.xml文件中基础配置有springMVC配置的servlet路径 <servlet-name>SpringMVC</serv ...
- SpringMVC与Struts2配置区别
Spring MVC模型与Struts2模型应用: Html表单: 上述这两段代码无论是SpringMVC还是Struts2,都可以共用.而在请求响应处理类(也就是Controller)上的设计差 ...
- springmvc学习(二)——使用RequestMapper请求映射
本次内容是@RequestMapping,后面会有实例代码 Spring MVC 使用 @RequestMapping 注解为控制器指定可以处理哪些 URL 请求在控制器的类定义及方法定义处都可标注@ ...
- SpringMVC Ajax返回的请求json
的方式来解决在中国字符串乱码问题
1.org.springframework.http.converter.StringHttpMessageConverter类是类处理请求或相应的字符串.和默认字符集ISO-8859-1,所以当返回 ...
随机推荐
- HDP Spark2 HIVE3.1 的问题
HDP 上安装了 Hive3.1 和 Spark2, 提交 Spark 作业时,报找不到 Hive 中表的问题 但是查一了下 hive 表,明明是存在这个表的.查看日志,注意到如下的一段日志. 没修改 ...
- JDBC技术(汇聚页)
JDBC代表Java数据库连接(Java Database Connectivity),它是用于Java编程语言和数据库之间的数据库无关连接的标准Java API, 换句话说:JDBC是用于在Java ...
- MySQL中LOCATE用法
SELECT LOCATE('q', 'asqdfasdfser') 返回 3 SELECT LOCATE('q', 'asqdfasqdfser',4) 返回 8 SELECT * from my ...
- 【2】JMicro微服务-Hello World
如非授权,禁止用于商业用途,转载请注明出处作者:mynewworldyyl 1. 首先完成 JMicro微服务-RPC体验 的1到5步. 按默认方式启动ZK及Redis: JDK需要Java8及以上. ...
- leetcode-201-数字范围按位与
题目描述: 给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点). 示例 1: 输入: [5,7] ...
- java四行代码实现图片下载
如下: InputStream in = new URL("http://www.updown/thumbnail.jpg).openStream(); Path temp = Paths. ...
- FJWC2019 最短路
题目描述 有一张无向图,开始的时候所有边权为1,所有点没有权值,现在给定一个整数k,表示可以将k个点的点权设置为1,求点0到n-1的最短路最长是多少 Solution 网络流好题[然而本蒟蒻还是不会] ...
- SVN解决冲突的方法
SVN管理代码工具在群组合作开发的过程中,若多人同时修改一个文件,就会出现冲突的情况. 冲突演示: 有A.B两个用户,他们各自从svn服务器中检出了file.txt文件,此时A.B.服务器三个地方的f ...
- jni使用javap查看java类方法签名
在Jni开发中,需要回调给java层数据,因此使用java的方法签名是必不可少的. 快速定位java方法签名的方式: java方法签名由(函数参数列表)返回值组成. cmd运行:javap -s 字节 ...
- Chapter 6. Names
6.2. Names and Identifiers A name is used to refer to an entity declared in a program. There are two ...