- 手撕简易SpringMVC框架
mvc 整体架构
新建一个动态 Web 工程。整体机构如下:
-
- 手写自己的Dispather 类,继承 HttpServlet
@PackageScann
public class MyDispather extends HttpServlet {
private static final long serialVersionUID = -7154047248664853493L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doget" + req.getRequestURI() + ":==:" + req.getRequestURL());
resp.sendRedirect("/pages/index.html");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.err.println("dispather service()" + Thread.currentThread().getName());
String requestURI = req.getRequestURI();
if (requestURI.endsWith("/")) {
requestURI = requestURI.substring(0, requestURI.length() - 1);
}
if (IOCUtils.getUrlMaps().containsKey(requestURI)) {
Method method = IOCUtils.getUrlMaps().get(requestURI);
try {
method.invoke(IOCUtils.newInstance(method), req, resp);
} catch (Exception e) {
e.printStackTrace();
}
} else {
resp.getWriter().write("The URL NOT Found");
}
}
@Override
public void destroy() {
System.err.println("dispather destory()");
}
/**
* 获取所有的自定义注解类,并且实例化,并且收入BeanMap 中
*/
@Override
public void init() throws ServletException {
System.out.println("dispather init()");
// 获取扫描路径下所有的class文件,实例化注解的bean.
IOCUtils.getBasePackage(this.getClass());
IOCUtils.createBeanMaps();
}
}
-
- 自定义过滤器,处理请求乱码问题
public class MyServletFilter implements Filter {
@Override
public void destroy() {
System.out.println("=========过滤器销毁了=================");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
System.out.println("过滤器执行操作" + req.getQueryString());
req.setCharacterEncoding("utf-8");
// 解决浏览器中文乱码
res.setHeader("content-type", "text/html;charset=utf-8");
// 解决get请求乱码
MyRequestWarp reqs = new MyRequestWarp(req);
chain.doFilter(reqs, res);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器初始化");
}
}
-
- 自定义增强 HttpServletRequestWrapper 类,对请求的参数进行解码
public class MyRequestWarp extends HttpServletRequestWrapper {
private HttpServletRequest request;
public MyRequestWarp(HttpServletRequest request) {
super(request);
this.request = request;
}
// 对请求request 对象的数据进行统一编码
@Override
public Map<String, String[]> getParameterMap() {
// 获取请求方式
String method = request.getMethod();
if ("POST".equalsIgnoreCase(method)) {
try {
request.setCharacterEncoding("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Map<String, String[]> map = request.getParameterMap();
return map;
} else if ("get".equalsIgnoreCase(method)) {
// get请求单独对请求参数单个装换
Map<String, String[]> map = request.getParameterMap();
System.out.println(map + ">>>>");
if (map == null) {
return super.getParameterMap();
}
Set<String> keySet = map.keySet();
String[] value = null;
String utf = null;
try {
for (String string : keySet) {
value = map.get(string);
for (int i = 0; i < value.length; i++) {
// 字符串转码
utf = new String(value[i].getBytes("iso-8859-1"), "utf-8");
value[i] = utf;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return super.getParameterMap();
}
@Override
public String getParameter(String name) {
// 通过value获取值
String[] values = getParameterValues(name);
if (values != null) {
return values[0];
}
return super.getParameter(name);
}
@Override
public String[] getParameterValues(String name) {
// 通过map 集合获取值
Map<String, String[]> parameterMap = getParameterMap();
if (parameterMap != null) {
return parameterMap.get(name);
}
return super.getParameterValues(name);
}
}
-
- 自定义 注解 Controller ,Service,RequestMapping,AutoWired,packScann
– MyController 控制层注解
/**
* 自定义控制层注解
*
* @author Donald 2019/03/23 21:08:55
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyController {
String value() default "";
}
– MyService 服务层注解
/**
* 自动定义控制层
*
* @author Donald 2019/03/23 21:58:49
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyService {
String value() default "";
}
– MyRequestMapping 请求注解
/**
* 自定义请求url 映射
*
* @author Donald 2019/03/23 22:07:26
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
String value() default "";
}
– PackageScann包扫描注解
/**
* 包扫描注解
*
* @author Donald 2019/03/23 22:38:33
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PackageScann {
String value() default "";
}
– 参数自动注入注解
/**
* 自定义自动注入
*
* @author Donald 2019/03/23 22:07:39
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {
String value() default "";
}
-
- 核心IOC 容易类 处理对bean 的管理,请求映射
public class IOCUtils {
private IOCUtils() {}
private static HashMap<String, Object> beanMaps = new HashMap<>();
private static HashMap<String, Class<?>> classMaps = new HashMap<>();
private static HashMap<String, Method> urlMaps = new HashMap<>();
private static String basePackage = null;
private static Class<?> clazz = null;
public static HashMap<String, Object> getBeanMaps() {
return beanMaps;
}
public static HashMap<String, Method> getUrlMaps() {
return urlMaps;
}
public static HashMap<String, Class<?>> getClassMaps() {
return classMaps;
}
/**
* 获取扫描的包名。默认为dispather所在的包名
*
* @return
* @throws IOException
*/
public static void getBasePackage(Class<?> clazz) {
IOCUtils.clazz = clazz;
PackageScann annotation = clazz.getAnnotation(PackageScann.class);
if (annotation == null) {
return;
}
String className = clazz.getTypeName();
basePackage =
"".equals(annotation.value()) ? className.substring(0, className.lastIndexOf(".")) : annotation.value();
// 获取指定包下面的所有的class 文件
getClassFiles();
}
/**
* 获取包名及其子包下面的所有的class文件
*/
private static void getClassFiles() {
// 将com.feifan 转换成文件夹形式com/feifan 再类加载读取文件
String fileString = basePackage.replaceAll("\\.", "/");
// 得到com/feifan的绝对地址 、D:xxx/com/feifan
String rootPath = clazz.getClassLoader().getResource(fileString).getPath();
// 直留着com/feifan,拼接类全名
if (rootPath != null)
rootPath = rootPath.substring(rootPath.indexOf(fileString));
try {
Enumeration<URL> enumeration = clazz.getClassLoader().getResources(fileString);
while (enumeration.hasMoreElements()) {
URL url = (URL)enumeration.nextElement();
if (url.getProtocol().equals("file")) {
// 如果是文件
File file = new File(url.getPath().substring(1));
Scanner(file, rootPath);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 封装类名,字节码 classMaps
*
* @param file
* @param rootPath
*/
private static void Scanner(File file, String rootPath) {
File[] files = file.listFiles();
for (int i = 0; files != null && i < files.length; i++) {
File file2 = files[i];
if (file2.isDirectory()) {
Scanner(file2, rootPath + file2.getName() + "/");
} else {
if (file2.getName().endsWith(".class")) {
String classname = (rootPath + file2.getName()).replaceAll("/", ".");
// 去掉.class 后缀字节码存入
classname = classname.substring(0, classname.lastIndexOf("."));
try {
classMaps.put(classname, Class.forName(classname));
} catch (ClassNotFoundException e) {
// TODO 获取字节码文件异常
e.printStackTrace();
}
}
}
}
}
/**
* 生成自定义注解注解的bean
*/
public static void createBeanMaps() {
if (classMaps == null) {
return;
}
Class<?> clazz = null;
String pathRoot = "";
String path = "";
String beanKey = "";
for (Map.Entry<String, Class<?>> entry : classMaps.entrySet()) {
clazz = entry.getValue();
// 控制层注解
if (clazz.isAnnotationPresent(MyController.class)) {
if (clazz.isAnnotationPresent(MyRequestMapping.class)) {
pathRoot = clazz.getAnnotation(MyRequestMapping.class).value();
if (!pathRoot.startsWith("/")) {
pathRoot = "/" + pathRoot;
}
if (!pathRoot.endsWith("/")) {
pathRoot = pathRoot + "/";
}
}
// url 映射路径
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(MyRequestMapping.class)) {
path = method.getAnnotation(MyRequestMapping.class).value();
if (path.startsWith("/")) {
if (path.length() > 1) {
path = path.substring(path.indexOf("/") + 1);
} else {
path = "";
}
}
urlMaps.put(pathRoot + path, method);
}
}
beanKey = clazz.getSimpleName();
beanKey = beanKey.substring(0, 1).toLowerCase() + beanKey.substring(1);
try {
beanMaps.put(beanKey, clazz.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
// 服务层注解
if (clazz.isAnnotationPresent(MyService.class)) {
Class<?>[] classes = clazz.getInterfaces();
try {
for (Class<?> class1 : classes) {
beanKey = class1.getSimpleName();
beanKey = beanKey.substring(0, 1).toLowerCase() + beanKey.substring(1);
beanMaps.put(beanKey, clazz.newInstance());
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
createAutowried();
}
/**
* 自动注入参数
*/
private static void createAutowried() {
if (classMaps == null) {
return;
}
Class<?> clazz = null;
String parm = "";
String beanName = "";
for (Map.Entry<String, Class<?>> entry : classMaps.entrySet()) {
clazz = entry.getValue();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(MyAutowired.class)) {
parm = field.getType().toString();
parm = parm.substring(parm.lastIndexOf(".") + 1);
parm = parm.substring(0, 1).toLowerCase() + parm.substring(1);
beanName = clazz.getSimpleName();
beanName = beanName.substring(0, 1).toLowerCase() + beanName.substring(1);
try {
field.setAccessible(true);
field.set(beanMaps.get(beanName), beanMaps.get(parm));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
/**
* 获取当前方法的主类
*
* @param method
* @return
*/
public static Object newInstance(Method method) {
String simpleName = method.getDeclaringClass().getSimpleName();
simpleName = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
return beanMaps.get(simpleName);
}
}
-
- 业务逻辑实现
– service 接口
- 业务逻辑实现
public interface UserService {
void printf();
}
– service 实现类
@MyService
public class UserServiceImpl implements UserService {
@Override
public void printf() {
System.err.println("UserServiceImpl>>>>>>");
}
}
– controller 类
BaseController 用来获取请求里面的requst,response
public class BaseController {
protected HttpServletRequest request;
protected HttpServletResponse response;
protected void init(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
}
protected HttpServletRequest getRequest() {
return request;
}
protected HttpServletResponse getResponse() {
return response;
}
}
– 控制层
@MyController
@MyRequestMapping("my")
public class UserController extends BaseController {
@MyAutowired
private UserService UserService;
@MyRequestMapping("my")
public String getMy(HttpServletRequest req, HttpServletResponse resp) throws Exception {
System.out.println("进来了" + req.getRequestURL());
UserService.printf();
// resp.setHeader("content-type", "text/html;charset=utf-8");
resp.getWriter().write("恭喜你访问到控制层了>>>>" + req.getParameter("name"));
return "my";
}
}
-
- 配置Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>SmsInterface</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>com.feifan.MyDispather</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.feifan.Filter.MyServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
启动测试:
**
至此一波简易的mvc 弄完
**
链接:https://pan.baidu.com/s/1SzcMIrcOSxo7-S--UO3hWQ
提取码:ujg4