简单实现web的请求派发机制
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单实现web的请求派发机制相关的知识,希望对你有一定的参考价值。
web.xml定义
<!-- spring bean 配置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener><!-- 启动时,扫描注解,把定义的url和相应的处理class数据缓存-->
<listener>
<listener-class>com.util.listener.ContextLoaderListener</listener-class>
</listener><!-- 过滤 字符编码过滤 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.util.filter.CharCodeFilter</filter-class>
<init-param>
<param-name>characterEncoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping><!-- 请求派发servlet -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>com.util.dispatcher.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>1请求派发,web容器启动时扫描url注解
public class ContextLoaderListener implements ServletContextListener {
Logger log =LoggerFactory.getLogger(ContextLoaderListener.class);
@Override
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
log.info("context destroyed");
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
try {
new ContextRootName().setContextRootName(arg0.getServletContext().getContextPath());
//注解扫描
new AnnotationScanner().sannClasses();
//执行完controller后跳转试图的配置
new AnalysisView().AnalysisActionViewProperties();
} catch (ClassNotFoundException e) {
log.error(e.getMessage());
}
log.info("context inited");
}
}
2.1.1注解扫描
public class AnnotationScanner {
private static List<String> packages = new ArrayList<String>();
static{
packages.add("com.wqf.action.impl");
}
/** 要扫描的路径 */
private static List<String> paths = null;
//TODO 扫描到需要的类方法需要更改
public void sannClasses() throws ClassNotFoundException{
String rootPath=getClass().getResource("/").getFile().toString();
paths = getPaths();
for(String path:paths){
File rootFile = new File(path);
File [] files = rootFile.listFiles();
String packageName = path.replace(rootPath, "").replace(‘/‘, ‘.‘) + ".";
for(File f: files) {
String className = f.getName().substring(0, f.getName().indexOf(".class"));
Class<?> clazz = Class.forName(packageName+className);
parseClass(clazz);
}
}
}
public void parseClass(Class<?> clazz) {
String url1= "";
String url2= "";
Annotation[] annotations = clazz.getAnnotations();
for(Annotation annotation:annotations){
if(annotation.annotationType().getSimpleName().equals("NameSpace")){
NameSpace nameSpace = (NameSpace)annotation;
url1 = nameSpace.nameSpace();
}
}
Method[] methods = clazz.getDeclaredMethods();
for(Method method:methods){
Annotation[] methodannotations = method.getAnnotations();
for(Annotation annotation:methodannotations){
if(annotation.annotationType().getSimpleName().equals("RequestMapping")){
RequestMapping requestMapping = (RequestMapping)annotation;
url2 = requestMapping.mapping();
MapClassMethodBean data = new MapClassMethodBean();
data.setBean(clazz);
data.setM(method);
String url = modifyUrl(url1 + url2);
RequestData.setData(url, data);
}
}
}
}
private static String modifyUrl(String url){
return url;
}
//TODO 拿到路径要改为从xml配置文件读取
private List<String> getPaths(){
String rootPath=getClass().getResource("/").getFile().toString();
List<String> stringList = new ArrayList<String>();
for(String scanPackage:packages){
String tmpPath = scanPackage.replace(‘.‘, ‘/‘);
stringList.add(rootPath + tmpPath);
}
return stringList;
}
}
2.1.2controller和跳转到jsp页面的配置
///firstAction/test.do = test.jsp
public class AnalysisView {
private String viewPath = "/resource/viewNamesProp";
public void AnalysisActionViewProperties() {
Properties prop = new Properties();
FileInputStream in;
try {
String rootPath=getClass().getResource("/").getFile().toString();
in = new FileInputStream(rootPath + viewPath);
prop.load(in);
Iterator<String> it = prop.stringPropertyNames().iterator();
while (it.hasNext()) {
String key=it.next();
ViewNameData.setData(key, prop.getProperty(key));
}
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.核心派发servlet
public class DispatcherServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
Logger log = LoggerFactory.getLogger(DispatcherServlet.class);
IBaseAction action = null;
private String JSP = "jsp";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// log.error("禁止get请求");
// return;
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* 判断请求类型分给不同的Class进行派发
*/
// String suffix = "";
// if(actionName.indexOf(".") != -1){
// suffix = actionName.substring(actionName.indexOf(".") + 1,actionName.indexOf("?")== -1 ? actionName.length():actionName.indexOf("?") -1);
// }
// if(JSP.equals(suffix)){
// JspDispatcherServlet.getInstance().doPost(req, resp);
// return;
// }
try {// 捕捉异常不抛到前台
String actionName = req.getServletPath();
actionName = actionName.indexOf("?") == -1 ? actionName :actionName.substring(0, actionName.indexOf("?"));
/** 实际业务的class */
Class<?> clazz = null;
/** 实际业务的方法 */
Method method = null;
/** 前台传递的变量统一封装到context内 */
Context context = ContextFactory.createContext(req, resp);
// ProxyHandler handler = new ProxyHandler();
String url = actionName.indexOf(".") == -1 ?actionName:actionName.substring(0, actionName.indexOf("."));
// 根据请求找到相应的action
MapClassMethodBean classMethodBean = RequestData.getData(url);
if (classMethodBean == null) {
log.info("该URL 未配置");
sendRedirect(ViewNameData.getNotFoundPage(),req,resp);
return;
}
clazz = classMethodBean.getBean();
method = classMethodBean.getM();
CglibProxyHandler cglibProxy = new CglibProxyHandler();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(cglibProxy);
// Object target = clazz.cast(ac.getBean(clazz));
// handler.setTarget(target);
// Object o =
// Proxy.newProxyInstance(target.getClass().getClassLoader(),
// target.getClass().getInterfaces(),
// handler);
Object o = enhancer.create();
Method[] omethods = o.getClass().getDeclaredMethods();
for (Method omethod : omethods) {
if (omethod.getName().equals(method.getName())) {
try {
omethod.invoke(o, context);
} catch (IllegalAccessException e) {
log.warn(e.getMessage());
} catch (IllegalArgumentException e) {
log.warn(e.getMessage());
} catch (InvocationTargetException e) {
log.warn(e.getMessage());
}
}
}
// 如果有对应的视图,跳转的相应的视图
String viewName = ViewNameData.getData(actionName);
if (viewName != null) {
sendRedirect(viewName,req,resp);
}
// 如果没有对应的视图
} catch (Exception e1) {
log.error(e1.getMessage());
sendRedirect(ViewNameData.getErrorPage(),req,resp);
}
}
private void sendRedirect(String fordardPage,HttpServletRequest req, HttpServletResponse resp) throws IOException{
String rootUrl = req.getScheme() + "://" + req.getServerName()
+ ":" + req.getServerPort()
+ req.getContextPath();
resp.sendRedirect(rootUrl + "/" + fordardPage);
}
}
总结:web容器启动的时候通过listener扫描contrller所在包的注解,形成Map<String url, BeanMethod<Class controller, String method>>的数据,请求来的时候走DispatcherServlet,根据请求的url找到相应的controller和method处理请求。
如果请求后配置的有相应jsp页面跳转到相应的jsp页面。
一个简单实现,比较差。各位看官权当娱乐,工程代码后续再传,吐槽51job的审核!!!
以上是关于简单实现web的请求派发机制的主要内容,如果未能解决你的问题,请参考以下文章