查看: 650|回复: 0

[Java语言] Struts1教程之ActionMapping_动力节点Java学院整理

发表于 2017-10-2 07:52:00
尚学堂AD

首先断点走出了processpath方法,

这个方法是用来截取字符串的,今天我们来看怎样获得ActionMapping的方法---processMapping。

在此之前简单说一下ActionMapping,它的源代码中可以看出,其中最重要的属性和我们的mvc小实例中的ActionMapping类似,都是有path、type还有forwardMap,主要是对应的struts-config配置文件而来,这个就是保存这个配置文件的信息到内存中。

具体的mvc小实例的ActionMapping代码如下:

  1. package com.cjq.servlet;
  2. import java.util.Map;
  3. public class ActionMapping {
  4. private String path;
  5. private Object type;
  6. private Map forwardMap;
  7. public String getPath() {
  8. return path;
  9. }
  10. public void setPath(String path) {
  11. this.path = path;
  12. }
  13. public Object getType() {
  14. return type;
  15. }
  16. public void setType(Object type) {
  17. this.type = type;
  18. }
  19. public Map getForwardMap() {
  20. return forwardMap;
  21. }
  22. public void setForwardMap(Map forwardMap) {
  23. this.forwardMap = forwardMap;
  24. }
  25. }
复制代码

而Struts中的Actionconfig(因为ActionMapping是继承这个ActionConfig的,所以我们来看ActionConfig更加直接)的代码如下:

从这两部分代码来看,更加印证了我在开篇写的mvc小实例是一个struts框架的雏形。

讲完ActionMapping的一些内容后,相信对ActionMapping有所了解,那么系统是如何生成ActionMapping和如何找到ActionMapping的呢?这就是今天要说的整体:

我们看下web.xml中有一个2 配置信息,这个信息就是说明了但服务器已启动就动态读取struts-config配置文件把配置文件的信息put到ActionMapping中。所以当我们运行服务器的时候,我们在内存中已经存在对应struts-config配置文件信息对应的ActionMapping。今天就是要通过processMapping读取这个ActionMapping类。

进入断点调试,首先在processMapping方法上设置断点。

进入源代码中:

  1. /**
  2. * <p>Select the mapping used to process theselection path for this request
  3. * If no mapping can be identified, createan error response and return
  4. * <code>null</code>.</p>
  5. *
  6. * @param request The servlet request weare processing
  7. * @param response The servlet response weare creating
  8. * @param path The portion of the requestURI for selecting a mapping
  9. *
  10. * @exception IOException if an input/outputerror occurs
  11. */
  12. protectedActionMapping processMapping(HttpServletRequestrequest,
  13. HttpServletResponse response,
  14. String path)
  15. throws IOException {
  16. // Is there a mapping for this path?
  17. ActionMapping mapping = (ActionMapping)
  18. moduleConfig.findActionConfig(path);
  19. // If a mapping is found, put it in the request and return it
  20. if (mapping != null) {
  21. request.setAttribute(Globals.MAPPING_KEY, mapping);
  22. return (mapping);
  23. }
  24. // Locate the mapping for unknown paths (if any)
  25. ActionConfig configs[] = moduleConfig.findActionConfigs();
  26. for (int i = 0; i < configs.length; i++) {
  27. if (configs[i].getUnknown()) {
  28. mapping = (ActionMapping)configs[i];
  29. request.setAttribute(Globals.MAPPING_KEY, mapping);
  30. return (mapping);
  31. }
  32. }
  33. // No mapping can be found to process this request
  34. String msg = getInternal().getMessage("processInvalid");
  35. log.error(msg + " " + path);
  36. response.sendError(HttpServletResponse.SC_NOT_FOUND, msg);
  37. return null;
  38. }
复制代码

首先我们传入我们在上一步截取的路径,通过moduleConfig的findAction方法来查找ActionConfig,并且返回ActionMapping。具体代码是:

  1. ActionMapping mapping =(ActionMapping)
  2. moduleConfig.findActionConfig(path);
复制代码

如果找到,那么就讲ActionMapping存放到request的context中。代码:

  1. if (mapping != null) {
  2. request.setAttribute(Globals.MAPPING_KEY, mapping);
  3. return (mapping);
  4. }
复制代码

如果没有通过path找到mapping,则在Actionconfig中遍历为未知路径寻找mapping,如果找到则存放到request中,如果没有找到,则返回错误信息,具体代码如下:

  1. // Locate the mapping for unknownpaths (if any)
  2. ActionConfig configs[] = moduleConfigfindActionConfigs();
  3. for (int i = 0; i < configslength; i++) {
  4. if (configs[i].getUnknown()) {
  5. mapping = (ActionMapping)configs[i];
  6. request.setAttribute(Globals.MAPPING_KEY, mapping);
  7. return (mapping);
  8. }
  9. }
  10. // No mapping can be found to process this request
  11. String msg = getInternal().getMessage("processInvalid");
  12. log.error(msg + " " + path);
  13. response.sendError(HttpServletResponse.SC_NOT_FOUND, msg);
  14. return null;
复制代码

来看下ActionServlet中的一个方法processActionForm,当我们在截取字符串,再根据字符串取得ActionMapping(这是前两篇文章中介绍的)之后,我们就要用利用ActionMapping来创建ActionForm了,并且把ActionForm放到request或session中管理。

先来看具体struts中processActionForm方法的具体实现:

  1. /**
  2. * <p>Retrieve and return the <code>ActionForm</code> associatedwith
  3. * this mapping, creating and retaining oneif necessary. If there is no
  4. * <code>ActionForm</code> associated with this mapping,return
  5. * <code>null</code>.</p>
  6. *
  7. * @param request The servlet request weare processing
  8. * @param response The servlet response weare creating
  9. * @param mapping The mapping we are using
  10. */
  11. protectedActionForm processActionForm(HttpServletRequestrequest,
  12. HttpServletResponse response,
  13. ActionMapping mapping) {
  14. // Create (if necessary) a form bean to use
  15. ActionForm instance = RequestUtilscreateActionForm
  16. (request, mapping, moduleConfig, servlet);
  17. if (instance == null) {
  18. return (null);
  19. }
  20. // Store the new instance in the appropriate scope
  21. if (log.isDebugEnabled()) {
  22. log.debug(" Storing ActionForm bean instance in scope '" +
  23. mapping.getScope() + "' under attribute key '" +
  24. mapping.getAttribute() + "'");
  25. }
  26. if ("request".equals(mapping.getScope())) {
  27. request.setAttribute(mapping.getAttribute(), instance);
  28. } else {
  29. HttpSession session =requestgetSession();
  30. session.setAttribute(mapping.getAttribute(), instance);
  31. }
  32. return (instance);
  33. }
复制代码

这个方法的大体流程是:根据ActionMapping中的name名称查找ActionForm,如果配置了ActionForm,那么就到request或session中查找,如果在request或session中存在已经创建的ActionForm,那么将返回。如果不存在那么会根据ActionForm的完成路径采用反射进行创建,再将创建好的ActionForm放到request或session中,之后返回ActionForm。

具体我们可以跟随断点调试来看看这个方法是如何运行的。

先设置断点,之后进入processActionForm方法。

第一个步骤就是创建ActionForm:

  1. // Create (if necessary) a formbean to use
  2. ActionForm instance = RequestUtils.createActionForm
  3. (request, mapping, moduleConfig, servlet);
  4. if (instance == null) {
  5. return (null);
  6. }
复制代码

通过调用RequestUtils.createActionForm的方法把ActionMapping中的ActionForm字符串生成对象,并且返回。进入这段代码中:

  1. publicstaticActionForm createActionForm(
  2. HttpServletRequest request,
  3. ActionMapping mapping,
  4. ModuleConfig moduleConfig,
  5. ActionServlet servlet) {
  6. // Is there a form bean associated with this mapping?
  7. String attribute = mappinggetAttribute();
  8. if (attribute == null) {
  9. return (null);
  10. }
  11. // Look up the form bean configuration information to use
  12. String name = mapping.getName();
  13. FormBeanConfig config =moduleConfigfindFormBeanConfig(name);
  14. if (config == null) {
  15. log.warn("No FormBeanConfig found under '"+ name + "'");
  16. return (null);
  17. }
  18. ActionForm instance = lookupActionForm(request,attribute, mappinggetScope());
  19. // Can we recycle the existing form bean instance (if there is one)?
  20. try {
  21. if (instance != null && canReuseActionForm(instance,config)) {
  22. return (instance);
  23. }
  24. } catch(ClassNotFoundException e) {
  25. log.error(servlet.getInternal().getMessage("formBean",config.getType()), e);
  26. return (null);
  27. }
  28. return createActionForm(config,servlet);
  29. }
复制代码

方法首先定义变量name,并且从mapping中获取值,String name = mapping.getName();也就是我们实例中的LoginForm字符串。之后通过调用FormBeanConfig config =moduleConfig.findFormBeanConfig(name);这句话把相应的LoginForm字符串生成相应的对象。

这里要说明的是我们在struts-config配置文件中,配置过这样一个标签信息:

  1. <form-beans>
  2. <form-bean name="loginForm" type=".struts.LoginActionForm"/>
  3. </form-beans>
复制代码

这个标签在服务器一启动的时候就会利用digester读取这里的配置信息,并且放在FormBeanConfig类中,这样我们可以通过上面那一句话就可以把LoginForm字符串生成相应的对象。

之后调用了ActionForm instance = lookupActionForm(request,attribute, mapping.getScope());这个方法,这个方法主要是查找scope属性中有没有存在ActionForm。具体实现:

  1. if ("request".equals(scope)){
  2. instance = (ActionForm)request.getAttribute(attribute);
  3. } else {
  4. session = request.getSession();
  5. instance = (ActionForm)session.getAttribute(attribute);
  6. }
复制代码

这里判断scope属性值是否为request,如果是则从request中读出ActionForm,如果不是则从session中读出。程序如果是第一次执行,那么ActionForm会是为空的。因为这里的ActionForm为空,所以就进入了if判断语句中,最后通过调用return createActionForm(config, servlet);创建ActionForm并且返回。

之后processActionForm就会把返回来的ActionForm放入request或者session中。具体实现就是:

  1. if ("request".equals(mapping.getScope())){
  2. request.setAttribute(mapping.getAttribute(), instance);
  3. } else {
  4. HttpSession session =request.getSession();
  5. session.setAttribute(mapping.getAttribute(), instance);
  6. }
复制代码

到此为止,ActionForm就创建完成,当ActionForm创建完成之后,就要用其他的方法来往ActionForm中赋值了



回复

使用道具 举报