自定义MVC框架中的一些元素
一些注解
代码语言:javascript复制@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 "";
}
处理对象封装
代码语言:javascript复制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处理代码
代码语言:javascript复制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;
}
}
测试代码
代码语言:javascript复制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配置
代码语言:javascript复制<!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的配置
代码语言:javascript复制scanPackage=com.zhao.mvcdemo
pom文件的配置
代码语言:javascript复制<?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/deme-code/tree/main/mvc