前言:为了深入web原理,本项目没有使用框架,主要描述了从请求到页面展现的思路,详情请见文末的具体项目

一、为什么要用filter?直接servlet实现不就行了

因为天猫这样的项目需要很多servlet处理具体种类的业务,比如后台的管理页面有增删改查,订单页面也有增删改查,每一个操作都需要写一个servlet。使用filter+反射可以解决这个冗余的问题。

二、从浏览器输入路径到filter

举个例子,我们本地天猫项目的首页地址为http://127.0.0.1:8080/tmall/forehome,tmall此处是项目名,我们在web.xml设置filter拦截所有请求,url-pattern设置的/*,所有请求都会映射到tmall.filter.ForeServletFilter这个Java类。

    <filter>
<filter-name>ForeServletFilter</filter-name>
<filter-class>tmall.filter.ForeServletFilter</filter- class>
</filter>
<filter-mapping>
<filter-name>ForeServletFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

在filter的doFilter方法里面判断请求,如是/fore开头的,跳转到前台对应的servlet再做具体逻辑数据处理。

@WebFilter(filterName = "ForeServletFilter")
public class ForeServletFilter implements Filter {
@Override
public void destroy() {
} @Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//获取从项目名开始的路径
String uri = request.getRequestURI();
//获取项目名路径
String contextPath = request.getContextPath();
//获得路径后缀
String path = StringUtils.remove(uri, contextPath);
if(path.startsWith("/fore")&&!path.startsWith("/foreServlet")) {
//需要将方法名取出并且放到session里面
String method = StringUtils.substringAfterLast(path, "fore");
request.setAttribute("method", method);
//跳转向foreServlet
request.getRequestDispatcher("/foreServlet").forward(request, response);
return;
}
chain.doFilter(request, response); } @Override
public void init(FilterConfig config) throws ServletException { } }

三、从filter跳转到servlet

web.xml设置servlet映射,跳转后来到ForeServlet这个Java类。

    <servlet>
<servlet-name>ForeServlet</servlet-name>
<servlet-class>tmall.servlet.ForeServlet</servlet-class>
</servlet> <servlet-mapping>
<servlet-name>ForeServlet</servlet-name>
<url-pattern>/foreServlet</url-pattern>
</servlet-mapping>

这里我们只写具体方法而不写service方法,让它继承其父类BaseForeServlet的service方法。这里的具体方法就包括了前面所说的各种后台的管理页面和订单页面的增删改查方法,此处举个首页的例子,定义一个home()方法:

public class ForeServlet extends BaseForeServlet {
public String home(HttpServletRequest request, HttpServletResponse response, Page page) {
List<Category> cs = categoryDAO.list(page.getStart(), page.getCount());
//填充数据
request.setAttribute("cs", cs);
new ProductDAO().fill(cs);
new ProductDAO().fillByRow(cs);
return "home.jsp";
}
}

四、使用反射调用具体方法

那么是如何调用到这个子类servlet的home()方法的呢?

这里我们通过BaseForeServlet的service方法,首先截取路径里面的方法名,然后使用反射执行子类的home()方法,将数据填充好。

@WebServlet(name = "BaseForeServlet")
public abstract class BaseForeServlet extends HttpServlet { protected CategoryDAO categoryDAO = new CategoryDAO();
protected OrderDAO orderDAO = new OrderDAO();
protected OrderItemDAO orderItemDAO = new OrderItemDAO();
protected ProductDAO productDAO = new ProductDAO();
protected ProductImageDAO productImageDAO = new ProductImageDAO();
protected PropertyDAO propertyDAO = new PropertyDAO();
protected PropertyValueDAO propertyValueDAO = new PropertyValueDAO();
protected ReviewDAO reviewDAO = new ReviewDAO();
protected UserDAO userDAO = new UserDAO();
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = (String)req.getAttribute("method");
Method md = null;
Page page = new Page(1, 5);
try {
md = this.getClass().getMethod(method, javax.servlet.http.HttpServletRequest.class,
javax.servlet.http.HttpServletResponse.class, Page.class);
String redirect = md.invoke(this, req, resp, page).toString();
if (redirect.startsWith("@")) {
resp.sendRedirect(redirect);
}else if (redirect.startsWith("%")) {
resp.sendRedirect(redirect);
}else {
req.getRequestDispatcher(redirect).forward(req, resp);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}

五、页面呈现

foreServlet返回home.jsp到父类,父类判断路径前缀,然后跳转到对应的页面。

String redirect = md.invoke(this, req, resp, page).toString();
if (redirect.startsWith("@")) {
resp.sendRedirect(redirect);
}else if (redirect.startsWith("%")) {
resp.sendRedirect(redirect);
}else {
req.getRequestDispatcher(redirect).forward(req, resp);
}

四、总结

本项目我们还暗含了MVC的设计模式,Model是Dao、Bean等数据,View是jsp页面,Control是servlet。因为篇幅有限,很多内容都没有展示,具体项目详见网上一个大神的项目:天猫J2EE项目

基于servlet+filter+反射模拟实现天猫首页的后端的更多相关文章

  1. servlet/filter/listener/interceptor区别与联系

    转自:http://www.cnblogs.com/doit8791/p/4209442.html servlet.filter.listener是配置到web.xml中(web.xml 的加载顺序是 ...

  2. 【转】servlet/filter/listener/interceptor区别与联系

    原文:https://www.cnblogs.com/doit8791/p/4209442.html 一.概念: 1.servlet:servlet是一种运行服务器端的java应用程序,具有独立于平台 ...

  3. 基于servlet实现一个web框架

    servlet作为一个web规范.其本身就算做一个web开发框架,可是其web action (响应某个URI的实现)的实现都是基于类的,不是非常方便,而且3.0之前的版本号还必须通过web.xml配 ...

  4. [转]web.xml中servlet ,filter ,listener ,interceptor的作用与区别

    原文链接:https://blog.csdn.net/netdevgirl/article/details/51483273 一.概念: 1.servlet:servlet是一种运行服务器端的java ...

  5. 过滤器(servlet.filter)和拦截器(springmvc.interceptor)区别

    ①拦截器是基于java的反射机制的,而过滤器是基于函数回调. ②拦截器不依赖与servlet容器,过滤器依赖与servlet容器. ③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求 ...

  6. 理解Servlet过滤器 (javax.servlet.Filter)

    过滤器(Filter)的概念 过滤器位于客户端和web应用程序之间,用于检查和修改两者之间流过的请求和响应. 在请求到达Servlet/JSP之前,过滤器截获请求. 在响应送给客户端之前,过滤器截获响 ...

  7. Servlet Filter 中init和destroy问题

    测试源码如下: package com.FilterTest.Filter; import java.io.IOException; import javax.servlet.Filter; impo ...

  8. 基于Servlet体系的HTTP请求代理转发Spring Boot组件

    背景概述 两个项目组原本都是各自负责两个产品线(产品A.产品B),由于公司业务的发展,目前需要将两个产品合并成一个大产品(功能整合,部分做取舍,最终产出产品C),前后端代码必然也需要整合,包括两个产品 ...

  9. java Servlet Filter 拦截Ajax请求

    /** * 版权:Copyright 2016-2016 AudaqueTech. Co. Ltd. All Rights Reserved. * 描述: * 创建人:赵巍 * 创建时间:2016年1 ...

随机推荐

  1. nginx篇最初级用法之nginx升级

    在不破坏nginx应用程序和配置文件下时,升级nginx. 下载新版本的nginx对其进行编译 使用nginx -V参数获得当前版本和配置参数 nginx version: nginx/1.10.3b ...

  2. StrGame

    如果先手可以控制一轮必胜或者必败,则先手必胜 如果只有必胜的方法,不能保证必败,则最后一轮的先手获得胜利,倒数第二轮的先手会被后手想办法”被胜利“从而在最后一轮成为后手,必败.倒数第三轮先手故意胜利, ...

  3. 微服务架构~Zuul1.0和2.0我们该如何选择?

    介绍 在今年5月中,Netflix终于开源了它的支持异步调用模式的Zuul网关2.0版本,真可谓千呼万唤始出来.从Netflix的官方博文[附录1]中,我们获得的信息也比较令人振奋: The Clou ...

  4. Java基础系列4:抽象类与接口的前世今生

    该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 1.抽象类: 当编写 ...

  5. windows使用docker运行mysql等工具(二)安装运行mysql

    今天接着上一篇的内容继续来学习安装运行mysql.建议先阅读第一篇:windows安装docker 一 查看mysql版本 如果想知道mysql镜像具体有哪几个版本,需要去docker hub查看. ...

  6. Vue基础系列(二)——Vue中的methods属性

      写在前面的话: 文章是个人学习过程中的总结,为方便以后回头在学习. 文章中会参考官方文档和其他的一些文章,示例均为亲自编写和实践,若有写的不对的地方欢迎大家指出. 作者简介: 一个不知名的前端开发 ...

  7. php imagick生成图片需要注意的问题

    php imagick生成图片需要注意的问题 坐标必须写死不要写自适应 这样才能达到效果图的最好效果 而且不会出现各种问题如果前端显示的生成图片不达标 可以再写一套代码 把后台生成的图片透明度设成0 ...

  8. websocket socketJs

    springboot实现服务器端消息推送(websocket + sockjs + stomp)   服务器端推送技术在web开发中比较常用,可能早期很多人的解决方案是采用ajax向服务器轮询消息,这 ...

  9. C语言I博客作业08

    这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 作业 我在这个课程的目标是 熟悉使用while和do-while结构解决问题 这个作业在那个具体方面帮助我实现目标 pta题目及查找的资料 ...

  10. RTX消息提醒工具设计文档

    为什么要做 项目上线后,系统依然由各业务模块负责人自己维护.而后台运行的各种业务服务结果,不能及时反馈到业务负责人.而等到客户反馈时则会太被动.为了能及时发现并解决项目问题,设计了该工具. 可利用资源 ...