自定义 MVC 框架中的一些元素
一些注解
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {String value () default "";
}
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {String value () default "";
}
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {String value () default "";
}
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {String value () default "";
}
解决对象封装
public class Handler {
private Object controller;//Controller 对应的类
private Method method;// 执行业务的办法
private Pattern pattern;//uri
private Map<String,Integer> paramIndexMapping;// 参数和地位的映射
public Handler(Object controller, Method method, Pattern pattern) {
this.controller = controller;
this.method = method;
this.pattern = pattern;
this.paramIndexMapping = new HashMap<>();}
public Object getController() {return controller;}
public void setController(Object controller) {this.controller = controller;}
public Method getMethod() {return method;}
public void setMethod(Method method) {this.method = method;}
public Pattern getPattern() {return pattern;}
public void setPattern(Pattern pattern) {this.pattern = pattern;}
public Map<String, Integer> getParamIndexMapping() {return paramIndexMapping;}
public void setParamIndexMapping(Map<String, Integer> paramIndexMapping) {this.paramIndexMapping = paramIndexMapping;}
}
自定义 DisptchServelet 解决代码
public class DispatchServelet extends HttpServlet {private Properties properties = new Properties();
private List<String> classNames = new ArrayList<>();
private Map<String,Object> ioc =new HashMap<>();
private List<Handler> handlerMapping = new ArrayList<>();
@Override
public void init(ServletConfig config) throws ServletException {
// 加载配置文件
String contextConfigLocation = config.getInitParameter("contextConfigLocation");
doLoadConfig(contextConfigLocation);
// 扫描相干的类,扫描注解
doScan(properties.getProperty("scanPackage"));
// 初始化 bean, 基于注解
doInstance();
// 实现依赖注入
doAutoWired();
// 实现处理器映射器,将 url 和 method 进行关联
initHandlerMapping();
System.out.println("mvc 初始化实现");
}
// 执行的是办法和 url 办法映射
private void initHandlerMapping() {if (ioc.isEmpty()){return;}
for (Map.Entry<String,Object> entry :ioc.entrySet()){Class<?> aClass = entry.getValue().getClass();
if (!aClass.isAnnotationPresent(Controller.class)){continue;}
String baseUrl = "";
if (aClass.isAnnotationPresent(RequestMapping.class)){RequestMapping requestMapping = aClass.getAnnotation(RequestMapping.class);
baseUrl=requestMapping.value();}
Method[] methods= aClass.getMethods();
for (int i=0;i<methods.length;i++){Method method = methods[i];
if (!method.isAnnotationPresent(RequestMapping.class)){continue;}
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
String methodUrl = requestMapping.value();
String url = baseUrl+methodUrl;
Handler handler = new Handler(entry.getValue(),method, Pattern.compile(url));
Parameter[] parameters = method.getParameters();
for (int j=0;j<parameters.length;j++){Parameter parameter = parameters[j];
if (parameter.getType().equals(HttpServletRequest.class)||parameter.getType().equals(HttpServletResponse.class)){handler.getParamIndexMapping().put(parameter.getType().getSimpleName(),j);
}else {handler.getParamIndexMapping().put(parameter.getName(),j);
}
}
// 实现办法和 url 的映射关系
handlerMapping.add(handler);
}
}
}
// 执行注入局部,同样是做的 ioc 的局部性能
private void doAutoWired() {if (ioc.isEmpty()){return;}
for (Map.Entry<String,Object> entry :ioc.entrySet()){Field[] declareFields = entry.getValue().getClass().getDeclaredFields();
for (int i=0;i<declareFields.length;i++){Field declareField = declareFields[i];
if (!declareField.isAnnotationPresent(Autowired.class)){continue;}
Autowired autowired = declareField.getAnnotation(Autowired.class);
String beanName = autowired.value();
if ("".equals(beanName.trim())){beanName=declareField.getType().getName();}
declareField.setAccessible(true);
try {
// 间接将这个字段的值设置为 ioc 中曾经示例化的类,// 即是实现了 ioc 中的实例化交给容器来治理的状况
declareField.set(entry.getValue(),ioc.get(beanName));
} catch (IllegalAccessException e) {e.printStackTrace();
}
}
}
}
// 执行的是符合要求的类的初始化,实际上是实现的一部分 ioc 的性能
private void doInstance() {if (classNames.size()==0){return;}
try {for (int i=0;i<classNames.size();i++){String className = classNames.get(i);
Class<?> clazz = Class.forName(className);
if (clazz.isAnnotationPresent(Controller.class)){String simpleName = clazz.getSimpleName();
String lowerFirst = lowerFirst(simpleName);
Object o = clazz.newInstance();
// 因为 controller 无别名,所以简略设置成首字母小写就行
ioc.put(lowerFirst,o);
}else if (clazz.isAnnotationPresent(Service.class)){Service service = clazz.getAnnotation(Service.class);
String beanName =service.value();
if (!"".equals(beanName.trim())){ioc.put(beanName,clazz.newInstance());
}else {beanName = lowerFirst(clazz.getSimpleName());
ioc.put(beanName,clazz.newInstance());
}
Class<?>[] interfaces = clazz.getInterfaces();
for (int j=0;j<interfaces.length;j++){Class<?> ainterface = interfaces[j];
System.out.println(ainterface.getName());
// 将实现类和接口进行绑定
ioc.put(ainterface.getName(),clazz.newInstance());
}
}else {continue;}
}
}catch (Exception e){e.printStackTrace();
}
}
private String lowerFirst(String className){char[] chars = className.toCharArray();
if ('A'<chars[0]&&chars[0]<'Z'){chars[0]+=32;
}
return new String(chars);
}
private void doScan(String basePackage) {
// 获取到指定包下的所有类的类名
String scanPackagePath= Thread.currentThread().getContextClassLoader().getResource("").getPath()+basePackage.replaceAll("\\.","/");
File pack = new File(scanPackagePath);
File [] files = pack.listFiles();
for (File file:files){if (file.isDirectory()){doScan(basePackage+"."+file.getName());
}else if (file.getName().endsWith(".class")){String className = basePackage+"."+file.getName().replaceAll(".class","");
classNames.add(className);
}
}
}
// 实现加载 web.xml 中配置的文件的门路
private void doLoadConfig(String contextConfigLocation) {InputStream inputStream =this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
try {properties.load(inputStream);
} catch (IOException e) {e.printStackTrace();
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Handler handler = getHander(req);
if (handler==null){resp.getWriter().write("404 not found");
return;
}
Class<?> [] parameterTypes = handler.getMethod().getParameterTypes();
Object[] paraValues = new Object[parameterTypes.length];
Map<String,String[]> parameterMap = req.getParameterMap();
for (Map.Entry<String,String[]> param:parameterMap.entrySet()){String value = StringUtils.join(param.getValue(),",");
if (!handler.getParamIndexMapping().containsKey(param.getKey())){continue;}
// 对应理论参数的地位
Integer index = handler.getParamIndexMapping().get(param.getKey());
paraValues[index]=value;
}
// 对应上 req, 和 resp 参数的地位
int reqIndex = handler.getParamIndexMapping().get(HttpServletRequest.class.getSimpleName());
paraValues[reqIndex]=req;
int respIndex = handler.getParamIndexMapping().get(HttpServletResponse.class.getSimpleName());
paraValues[respIndex]=resp;
try {
// 理论执行的是 controller 中的办法
handler.getMethod().invoke(handler.getController(),paraValues);
System.out.println("执行 controller 办法胜利");
} catch (IllegalAccessException e) {e.printStackTrace();
} catch (InvocationTargetException e) {e.printStackTrace();
}
}
private Handler getHander(HttpServletRequest req) {if (handlerMapping.isEmpty()){return null;}
String url =req.getRequestURI();
for (Handler handler:handlerMapping){Matcher matcher = handler.getPattern().matcher(url);
if (!matcher.matches()){continue;}
return handler;
}
return null;
}
}
测试代码
public interface DemoService {String getName(String name);
}
@Service("demoService")
public class DemoServiceImpl implements DemoService {
@Override
public String getName(String name) {return name;}
}
@Controller
@RequestMapping("/demo")
public class DemoController {
@Autowired
private DemoService demoService;
@RequestMapping("/query")
public String query(HttpServletRequest req, HttpServletResponse resp,String name){return demoService.getName(name);
}
}
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>mvc</servlet-name>
<servlet-class>com.zhao.mvcframework.servelet.DispatchServelet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>mvc.properties</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
mvc.properties 的配置
scanPackage=com.zhao.mvcdemo
pom 文件的配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zhao</groupId>
<artifactId>mvc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>mvc Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/</path>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
<compilerArgs>-parameters</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
测试时拜访具体的 http://localhost:8080/demo/query?name=zhaozhen 无问题
代码地址为 https://github.com/zhendiao/d…
欢送搜寻关注自己与敌人共同开发的微信面经小程序【大厂面试助手】和公众号【微瞰技术】