基于注解yaml配置手动实现简单的springmvc,实现bean注入功能,mvc实体类参数接收
项目github地址:https://github.com/kongGe55/spring-mvc-test
整个项目只依赖了javaweb相关jar包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>servlet-api</artifactId>
<version>6.0.29</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.yaml/snakeyaml -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.17</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
</dependencies>
不完善的地方
- 实体类参数接受只支持String类型和Interger,后期可以加上其他参数类型接收,支持类型有限;
- 只支持注解
- 还很多不完善的地方望指正,我也是在学习反射的使用
使用方法和springmvc一样,只不过配置文件要在resource下,名称application.yaml
配置web.xml
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>DispacherServlet</servlet-name>
<servlet-class>com.ji.spring.springmvc.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispacherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
applicetion配置
springmvc :
application :
# 要扫描的包名
scanPackage : com.ji.test
实现效果
实体类参数注入效果
实体类
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
测试controller
@Controller
@RequestMapping("test")
public class TestController {
@AutoWired
private TestService testService;
@RequestMapping("demo")
public void success(){
System.out.println("访问成功!111111111111111111111");
}
@RequestMapping("user")
public User user(@RequestParam("age")Integer i,@RequestParam("name") String name ,User user) {
System.out.println(user);
System.out.println(i);
System.out.println();
System.out.println(name);
return user;
}
}
访问效果
bean自动注入效果
controller
@Controller
@RequestMapping("user")
public class UserController {
@AutoWired
private UserService userService;
@RequestMapping("findUser")
public List<User> findUser(HttpServletResponse response) throws IOException {
List<User> list = userService.findUser();
return list;
}
}
这里返回数据自动进行了处理
Service
@Component("userService") //也可以直接用@Service注解
public class UserService {
public List<User> findUser(){
User user1 = new User();
user1.setAge(23);
user1.setName("测试1");
User user2 = new User();
user2.setAge(23);
user2.setName("测试2");
User user3 = new User();
user3.setAge(55);
user3.setName("测试3");
List<User> list = new ArrayList<>();
list.add(user1);
list.add(user2);
list.add(user3);
return list;
}
}
访问效果
基本包
下面是相关代码,具体项目可以到gihub下载https://github.com/kongGe55/spring-mvc-test
首先是相关注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoWired {
String value() default "";
}
------------------------------------------------
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value();
}
--------------------------------------------------------
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
}
----------------------------------------------------------------
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}
------------------------------------------------------------
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String value() default "";
}
---------------------------------------
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestParam {
String value() default "";
}
然后是核心的DispatcherServlet相关代码
package com.ji.spring.springmvc.servlet;
import com.ji.spring.core.annotation.AutoWired;
import com.ji.spring.core.annotation.Component;
import com.ji.spring.core.annotation.Service;
import com.ji.spring.springmvc.annotation.Controller;
import com.ji.spring.core.bean.SpringMvcBeanFactory;
import com.ji.spring.core.bean.BeanFactory;
import com.ji.spring.springmvc.annotation.RequestMapping;
import com.ji.spring.springmvc.annotation.RequestParam;
import org.yaml.snakeyaml.Yaml;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.security.KeyStore;
import java.util.*;
public class DispatcherServlet extends HttpServlet {
private List<String> classNameList = new ArrayList<String>();
private Map<String,HandlerMapping> handlerMappings = new HashMap<>();
HttpRequestHandler httpRequestHandler;
@Override
public void init() throws ServletException {
//扫描包下的类
try {
initClassNameList();
} catch (FileNotFoundException e) {
System.out.println("没有找到配置文件");
}
//初始化bean容器
initBeans();
//初始化属性注入
initWired();
//初始化HandlerMapping
initHandlerMapping();
httpRequestHandler = new HttpRequestHandler();
}
private void initHandlerMapping() {
//遍历bean容器
SpringMvcBeanFactory beanFactory = (SpringMvcBeanFactory) SpringMvcBeanFactory.getBeanFactory();
Set<String> set = beanFactory.keySet();
for (String key:set){
Object bean = beanFactory.getBean(key);
Class beanClass = bean.getClass();
if (beanClass.isAnnotationPresent(Controller.class)){
//如果是controller
String url = "/";
if (beanClass.isAnnotationPresent(RequestMapping.class)){
//判断类上RequestMapping路径
RequestMapping requestMapping = (RequestMapping) beanClass.getAnnotation(RequestMapping.class);
String tem = requestMapping.value();
url = url+tem+"/";
}
//判断方法上RequestMapping路径
Method[] methods = beanClass.getDeclaredMethods();
for (Method method:methods){
if (method.isAnnotationPresent(RequestMapping.class)){
RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);
String s = methodAnnotation.value();
String url_tem = url;
url_tem += s;
url_tem.replaceAll("//", "/");
HandlerMapping handlerMapping = new HandlerMapping(bean,method);
handlerMappings.put(url_tem,handlerMapping);
}
}
}
}
}
private Object[] searchParam(Method method, HttpServletRequest req, HttpServletResponse resp) {
//获取方法上的参数类型并生成参数
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] args = new Object[parameterTypes.length];
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int j=0;j<parameterTypes.length;j++){
String simpleName = parameterTypes[j].getSimpleName();
switch (simpleName){
case "HttpServletRequest":
args[j] = req;
break;
case "HttpServletResponse":
args[j]=resp;
break;
case "String":
RequestParam requestParam = getRequestParamAnnotationByIndex(parameterAnnotations,j);
String param_Name = requestParam.value();
String str = req.getParameter(param_Name);
if (!isEmpty(str)){
args[j] = str;
}
break;
case "Integer":
RequestParam requestParam1 = getRequestParamAnnotationByIndex(parameterAnnotations,j);
String param_Name1 = requestParam1.value();
String parameter = req.getParameter(param_Name1);
if (!isEmpty(parameter)){
args[j] = (Integer)Integer.parseInt(parameter);
}
break;
default:
for (String s:classNameList){
if (s.endsWith(simpleName)){
simpleName = s;
}
}
Class t = null;
try {
t = Class.forName(simpleName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.println("未找到参数实体类");
}
Object o = null;
try {
o = t.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
System.out.println("实体类实例化失败");
}
Field[] declaredFields = t.getDeclaredFields();
for (Field field : declaredFields){
String filed_name = field.getName();
Class<?> fieldType = field.getType();
field.setAccessible(true);
if(fieldType == String.class){
if (!isEmpty(req.getParameter(filed_name))){
try {
field.set(o,req.getParameter(filed_name));
} catch (IllegalAccessException e) {
e.printStackTrace();
System.out.println("实体类参数注入失败");
}
}
}else if (fieldType == Integer.class){
if (!isEmpty(req.getParameter(filed_name))){
try {
String parameter1 = req.getParameter(filed_name);
Integer i = Integer.parseInt(parameter1);
field.set(o,i);
} catch (IllegalAccessException e) {
e.printStackTrace();
System.out.println("实体类参数注入失败");
}
}
}
}
args[j] = o;
}
}
return args;
}
private RequestParam getRequestParamAnnotationByIndex(Annotation[][] parameterAnnotations,int j) {
for (Annotation annotation :parameterAnnotations[j]){
Class<? extends Annotation> type = annotation.annotationType();
if ("RequestParam".equals(type.getSimpleName())){
return (RequestParam) annotation;
}
}
return null;
}
//获取参数注解上索引对应参数的RequestMapping注解
private void initWired() {
SpringMvcBeanFactory beanFactory = (SpringMvcBeanFactory) SpringMvcBeanFactory.getBeanFactory();
Set<String> set = beanFactory.keySet();
for (String key:set){
Object bean = beanFactory.getBean(key);
Field[] fields = bean.getClass().getDeclaredFields();
if (fields.length>0){
for (Field field:fields){
if (field.isAnnotationPresent(AutoWired.class)){
String value = field.getAnnotation(AutoWired.class).value();
field.setAccessible(true);
try {
if (!"".equals(value)) {
field.set(bean, beanFactory.getBean(value));
}
field.set(bean, beanFactory.getBean(field.getName()));
}
catch (IllegalAccessException e) {
e.printStackTrace();
System.out.println("bean注入失败");
}
}
}
}
}
}
private void initBeans() {
//获取bean工厂
BeanFactory beanFactory = SpringMvcBeanFactory.getBeanFactory();
for (String className:classNameList){
Class bean = null;
try {
bean = Class.forName(className);
} catch (ClassNotFoundException e) {
System.out.println("没有找到类");
}
if (bean.isAnnotationPresent(Controller.class)||bean.isAnnotationPresent(Service.class)){
Object o = null;
try {
o = bean.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
System.out.println("生成实例化对象失败");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
beanFactory.setBean(o);
}
if (bean.isAnnotationPresent(Component.class)){
Component annotation = (Component) bean.getAnnotation(Component.class);
Object o = null;
try {
o = bean.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if ("".equals(annotation.value())){
beanFactory.setBean(o);
}else {
String name = annotation.value();
beanFactory.setBeanByName(name,o);
}
}
}
}
private void initClassNameList() throws FileNotFoundException {
//获取配置文件
URL resource = DispatcherServlet.class.getClassLoader().getResource("application.yaml");
Yaml yaml = new Yaml();
Map load = (Map) yaml.load(new FileInputStream(resource.getFile()));
Map application = (Map) load.get("springmvc");
Map scanPackage_map = (Map) application.get("application");
String scanPackage = (String) scanPackage_map.get("scanPackage");
scanClassList(scanPackage);
}
private void scanClassList(String scanPackage) {
URL url = DispatcherServlet.class.getClassLoader().getResource(scanPackage.replaceAll("\\.","/"));
File file = new File(url.getFile());
File[] files = file.listFiles();
for (File file_path:files){
if (file_path.isDirectory()){
scanClassList(scanPackage+"."+file_path.getName());
}else if (file_path.getName().endsWith(".class")){
classNameList.add(scanPackage+"."+file_path.getName().replace(".class", ""));
}
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String requestURI = req.getRequestURI();
HandlerMapping handlerMapping = handlerMappings.get(requestURI);
if (handlerMapping==null){
resp.getWriter().write("404 NOT FOUND");
return;
}
Object instance = handlerMapping.getController();
Method method = handlerMapping.getMethod();
Object[] args = searchParam(method, req, resp);
httpRequestHandler.invoke(instance,method,args,req,resp);
}
//判断字符串是否为空
public static boolean isEmpty(String s){
return (!"".equals(s)&&s!=null)?false:true;
}
}
BeanFactory bean工厂接口
package com.ji.spring.core.bean;
public interface BeanFactory {
void setBean(Object o);
Object getBean(String beanName);
void setBeanByName(String str,Object o);
}
SpringMvcBeanFactory工厂类
package com.ji.spring.core.bean;
import java.util.HashMap;
public class SpringMvcBeanFactory extends HashMap implements BeanFactory{
//单例
private static BeanFactory springMvcBeanFactory;
private void setSpringMvcBeanFactory(){};
public synchronized static BeanFactory getBeanFactory(){
if (springMvcBeanFactory == null){
springMvcBeanFactory = new SpringMvcBeanFactory();
}
return springMvcBeanFactory;
}
@Override
public void setBean(Object object) {
String name = object.getClass().getSimpleName();
name = firstWordToLowerCase(name);
this.put(name, object);
}
@Override
public void setBeanByName(String name,Object object){
this.put(name, object);
}
@Override
public Object getBean(String beanName) {
return this.get(beanName);
}
//首字母小写
public static String firstWordToLowerCase(String str){
String str_ = str.substring(0,1).toLowerCase()+str.substring(1);
return str_;
}
}
handler处理器接口
public interface Handler {
void invoke(Object instance, Method method, Object[] args, HttpServletRequest req, HttpServletResponse resp) throws Exception;
}
HttpRequestHandler处理器类
package com.ji.spring.springmvc.servlet;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class HttpRequestHandler implements Handler{
public void invoke(Object instance, Method method, Object[] args, HttpServletRequest req, HttpServletResponse resp) throws IOException {
Object invoke = null;
Class<?> type = method.getReturnType();
try {
invoke = method.invoke(instance, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
System.out.println("方法未声明public");
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if (invoke!=null){
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(invoke);
resp.setHeader("Content-Type", "application/json;charset=UTF-8");
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write(s);
}
}
}
HandlerMapping处理器映射类
package com.ji.spring.springmvc.servlet;
import java.lang.reflect.Method;
public class HandlerMapping {
private Object controller;
private Method method;
public HandlerMapping() {
}
public HandlerMapping(Object controller,Method method) {
this.controller = controller;
this.method = method;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Object getController() {
return controller;
}
public void setController(Object controller) {
this.controller = controller;
}
}