JavaEE中的MVC(五)定制Struts——Action跳转JSP
来源:互联网 发布:淘宝举报假冒及盗版 编辑:程序博客网 时间:2024/04/29 11:27
在JavaEE中的MVC(三)中,我在Servlet中引入了命令模式的使用,采用Xml配置的方式,实现了一个Servlet调用多个不同的Action类,但是还不能实现页面地跳转,这一篇博客从之前的代码上,进一步地封装,实现Action跳转Jsp的功能,并且介绍一下如何将我们客户端的参数,传给我们的Action。
注:本文并不讲解Struts框架,只研究这种思想,研究如何实现Struts框架的封装
JavaEE中的MVC(三)定制Struts——命令模式
改进思路
我们要想办法解决这些问题:
- Action内部不应该只有excute()一个方法,还可以有add()、delete()、update()等等,而且在执行完这些方法之后,能进行页面跳转,比如:执行完add()的时候,跳转到add.jsp页面;
- 在Xml配置文件上,我们应该为我们的Action节点,添加一个或者多个子节点,这个子节点可以命名为result,用以表示Action期望跳转的Jsp页面;
- 有对应的Javabean,解析完Xml配置之后,需要存储数据,自然需要Javabean。因为一个Action可能有多个Result,因此还要有对应的数据结构。
整体的流程就如下所示:客户端发送请求,Servlet负责解析Url,根据Url调用指定的Action,执行Action中相应的操作,执行完这一部分操作之后,会有一个返回值,根据返回值再跳转Jsp页面:
配置文件Plus
重新设计我们的配置文件,在Action节点下添加Result节点,Result拥有3个属性:
- name:当我们执行Action中的某一个方法的时候,会有一个返回值,返回值与name的值相对应;
- page:所要跳转的目标页面;
- redirect:跳转目标页面所用的方法是否是重定向。
<?xml version="1.0" encoding="UTF-8"?><mystruts> <action name="HiAction" class="com.action.HiAction"> <result name="success" page="Hello.jsp" redirect="true" /> <result name="add" page="Hi.jsp" /> <result name="delete" page="Hi.jsp" /> </action> <action name="HelloAction" class="com.action.HelloAction"> <result name="error" page="Hello.jsp" /> </action></mystruts>
Action类
这两个Action都继承自MyAction接口,其中HiAction中包含excute()以外的其它方法。
public interface MyAction { String SUCCESS = "success"; String NONE = "none"; String ERROR = "error"; String INPUTE = "inpute"; String LOGIN = "login"; String excute() throws Exception;}public class HelloAction implements MyAction{ @Override public String excute() { System.out.println("this is helloAction"); return ERROR; }}public class HiAction implements MyAction{ @Override public String excute() { System.out.println("this is hiAction:ERROR"); return ERROR; } public String add() { System.out.println("this is hiAction:add"); return "add"; } public String delete() { System.out.println("this is hiAction:delete"); return "delete"; }}
设计Javabean
ActionDifinition
我们原先的Javabean是Action,但是现在,我们的节点更加多样化,所以重新设计Javabean,取名叫ActionDifinition,ActionDifinition内部封装了Action和一个Result,因为Action和Jsp是一对多的关系,因此,将Result封装在Map中。
注:其中invoke(String methodName)和createAction()两个方法可以提取,单独创建工具类。
public class ActionDifinition { private MyAction mAction; private Map<String, Result> mResulteMap = new HashMap<String, Result>(); public void putResult(String key, Result value) { mResulteMap.put(key, value); } public Result getResult(String key){ return mResulteMap.get(key); } public void setAction(MyAction action) { this.mAction = action; } /** * 寻找并执行由Uri中指定的,Action中的方法,并且将返回值return */ public String invoke(String methodName) { try { if (methodName == null) return mAction.excute(); MyAction action=createAction(); Method[] methods = action.getClass().getDeclaredMethods(); for (Method method : methods) { if (methodName.equals(method.getName())) { return (String) method.invoke(action); } } } catch (Exception e) { e.printStackTrace(); } return null; } /** * 生成Action的备份,这一点前面提到了,因为希望不同用户的相同业务使用不同的Action */ private MyAction createAction() { try { return mAction.getClass().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; }}
Result
这个Javabean封装了我们希望跳转的Jsp页面的相关信息,内容与Xml配置文件相对应。
public class Result { private String name; private String page; private boolean redirect; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPage() { return page; } public void setPage(String page) { this.page = page; } public boolean isRedirect() { return redirect; } public void setRedirect(boolean redirect) { this.redirect = redirect; }}
ActionFactory改进
既然Xml配置文件换掉了,解析用的类自然也要换,原先内部所封装的Action,现在要替换成ActionDifinition。这个类是解析Xml文件的核心类,内部包含一个Map,用于存储Xml文件解析的Javabean。
public class ActionFactory { private static Map<String, ActionDifinition> actions = new HashMap<>(); private static ActionFactory factory; /** * 在静态块儿中就开始解析配置文件 */ static { parseFile("/my_struts.xml"); System.out.println(actions.toString()); } private ActionFactory() { //这个类中构造器反而是最后才执行的 System.out.println("======================"); System.out.println("信息:ActionFactory is OK"); } /** * 单例模式,构造器私有化 */ public static void init() { if (factory == null) { synchronized (ActionFactory.class) { if (factory == null) { factory = new ActionFactory(); } } } } public static ActionDifinition getAction(String actionName) throws Exception { return actions.get(actionName); } /** * 根据路径解析 */ private static void parseFile(String path) { try { InputStream inputStream = ActionFactory.class.getResourceAsStream(path); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(inputStream); NodeList beanNodeList = document.getElementsByTagName("action"); for (int i = 0; i < beanNodeList.getLength(); i++) { Node bean = beanNodeList.item(i); parseActionNodes(bean); } } catch (Exception e) { e.printStackTrace(); } } /** * 解析Action */ private static void parseActionNodes(Node node) { try { Element element = (Element) node; String name = element.getAttribute("name"); String className = element.getAttribute("class"); MyAction action = (MyAction) Class.forName(className).newInstance(); //往Map中加入ActionDifinition ActionDifinition actionDifinition=new ActionDifinition(); actionDifinition.setAction(action); //解析Result节点 parseResultNodes(actionDifinition, node); actions.put(name, actionDifinition); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 解析Result节点 */ private static void parseResultNodes(ActionDifinition actionDifinition, Node node) { NodeList resultNodeList = node.getChildNodes(); for (int j = 0; j < resultNodeList.getLength(); j++) { Node propertyNode = resultNodeList.item(j); if (propertyNode.getNodeType() == Node.ELEMENT_NODE && "result".equals(propertyNode.getNodeName())) { Element resultElement = (Element) propertyNode; String name = resultElement.getAttribute("name"); String page = resultElement.getAttribute("page"); String redirectStr = resultElement.getAttribute("redirect"); boolean redirect = redirectStr != null && "true".equals(redirectStr); Result result = new Result(); result.setName(name); result.setPage(page); result.setRedirect(redirect); actionDifinition.putResult(name, result); } } }}
中央控制器(Servlet)
和原先差不多,因为代码都封装掉了,这里的逻辑依旧很简单,就和开始说得一样,解析客户端传来的Url,根据Url然后找到Action,执行Action的方法,根据方法执行的结果,判断要跳转到哪一个Jsp页面。
//urlPatterns拦截规则我替换成action了@WebServlet(name = "PrepareAndExcuteServlet", urlPatterns = "/action/*")public class PrepareAndExcuteServlet extends HttpServlet { private static final long serialVersionUID = 1965314831568094829L; /** * 初始化的时候,顺带地把ActionFactory初始化好 */ @Override public void init() throws ServletException { super.init(); ActionFactory.init(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { // 对解析URI进行调整 String pathInfo = request.getPathInfo(); int index = pathInfo.indexOf('!'); String actionUri = pathInfo.substring(1, index == -1 ? pathInfo.length() : index); String resultUri = index == -1 ? null : pathInfo.substring(index + 1); // 根据URI找到对应的ActionDifinition,ActionDifinition内部封装了Action和Result ActionDifinition actionDifinition = ActionFactory.getAction(actionUri); // 执行Action中的方法,并且获取返回值 String resultStr = actionDifinition.invoke(resultUri); // 根据返回值,跳转指定的页面 Result result = actionDifinition.getResult(resultStr); if (result.isRedirect()) { response.sendRedirect("/" + result.getPage()); } else { request.getRequestDispatcher("/" + result.getPage()).forward(request, response); } } catch (Exception e) { e.printStackTrace(); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}
测试效果:
hi.jsp代码我就不发了,下面是测试的结果,客户端发送请求要在结尾加上:“action/HiAction!add”,action是过滤标志,HiAction是我们希望调用的那个Action,而add是Action中的方法,感叹号作为分隔符。
最后呢,蛮发一下我的工程目录吧。
Action接收参数
要想实现Action接收客户端传来的参数,其实通过之前提到的IOC即可,给我们的Action添加属性,然后写它的Set方法,然后注入值即可,需要注意的就是编码问题。
下面是遍历请求体的参数列表的方法
Enumeration<String> map = request.getParameterNames(); while (map.hasMoreElements()) { String param = (String) map.nextElement(); //Set方式注入值 setProperty(action, param, request.getParameter(param)); }
关于Set参数注入值的代码如下,其实这一段代码已经发过很多次了。
public void setProperty(Object instance, String name, String value) throws Exception { Class<?> clazz = instance.getClass(); Method[] methods = clazz.getMethods(); for (Method method : methods) { String methodName = method.getName(); if (("set" + name.substring(0, 1).toUpperCase() + name.substring(1)).equals(methodName)) { System.out.println("methodName" + methodName); method.invoke(instance, value); } } }
假如说我们的客户端会传来一个值,叫name,我们的Action想要接收这个值,我们的Action就要变成这样了:
public class HelloAction implements MyAction{ private String name; public void setName(String name) { this.name = name; } @Override public String excute() { System.out.println("this is helloAction"); return ERROR; }}
- JavaEE中的MVC(五)定制Struts——Action跳转JSP
- JavaEE中的MVC(三)定制Struts——命令模式
- struts中的JSP页面根据action跳转
- [JavaEE]Struts2路径问题(如何在jsp页面正确访问struts.xml中的action)
- JavaEE复习笔记(6)——Struts:Action
- struts/Servlet,action转到jsp后,路径问题(struts2,jsp路径,action路径,action跳转,相对路径,绝对路径)
- Struts jsp 遍历action中的数组
- struts中Action跳转jsp页面图片.css乱----解决方法
- struts-jsp-action 跳转后,无法适应CSS样式
- struts学习(5)——Action中的默认值
- struts/Servlet,action转到jsp后,CSS失效,路径问题(struts2,jsp路径,action路径,action跳转,相对路径,绝对路径)
- Struts/Servlet,action转到jsp后,CSS失效,路径问题(struts2,jsp路径,action路径,action跳转,相对路径,绝对路径)
- asp.net——MVC点击图片跳转Action
- Struts配置跳转action
- Servlet 和 Struts中的Action属于MVC中的C(Controler)
- JavaEE中的MVC(四)AOP代理
- JavaEE复习笔记(5)——Struts:MVC思想和Struts2的配置
- 总结一:jsp调用struts的action类中的map
- Leetcode Two Sum II - Input array is sorted
- Leetcode 27. Remove Element
- 【LeetCode】 110. Balanced Binary Tree
- 161220
- 【LeetCode】 111. Minimum Depth of Binary Tree
- JavaEE中的MVC(五)定制Struts——Action跳转JSP
- React-Native从入门到放弃(一)准备篇
- React-Native从入门到放弃(二)
- Leetcode 118. Pascal's Triangle
- [C++]Leetcode #8 atoi()
- date命令--Linux命令应用大词典729个命令解读
- compress命令--Linux命令应用大词典729个命令解读
- vgscan命令--Linux命令应用大词典729个命令解读
- sysctl命令--Linux命令应用大词典729个命令解读