1.多模块
许多规模庞大的系统,可能需要许多的模块,比如财务模块、客服模块、销售模块等等。一个struts-config文件就会显得十分乏力,那要如何配置多模块呢。
配置方法
-
建立单独的struts配置文件
-
在web.xml里面配置相应信息
2.1 增加一个参数名称为“config/模块名” 的参数,指明另一模块配置文件的文件路径
2.2 模块名称和目录名称需要一样
2.3
<init-param>
<param-name>config/submodule</param-name>
<param-value>WEB-INF/2.xml</param-value>
</init-param>
假设我们在一个大型商场系统里面设置了多个模块,除了默认的struts-congfig.xml,还有一个我们自己定义的struts-config-sale.xml,我们需要在web.xml中进行配置,代码如下:
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>config/sale</param-name>
<param-value>/WEB-INF/struts-config-sale.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
假设我们在struts-config.xml和struts-config-sale.xml中都设置名为"/query"的action,当我们在地址栏输入query.do的时候,系统是默认访问struts-config.xml中的query,如果想要让系统访问struts-config-sale.xml中的query,则需要在地址栏中增加"/sale",也就是模块在web.xml
中配置的名称。
struts-config.xm:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<form-bean name="queryForm" type="ActionForm.QueryForm"></form-bean>
</form-beans>
<action-mappings>
<action path="/query" name="queryForm" type="Action.QueryAction"></action>
</action-mappings>
</struts-config>
struts-config-sale.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<form-bean name="queryInSaleForm" type="ActionForm.QueryInSaleForm"></form-bean>
</form-beans>
<action-mappings>
<action path="/query" name="queryInSaleForm" type="Action.QueryInSaleAction"></action>
</action-mappings>
</struts-config>
QueryAcion.java:
package Action;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class QueryAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("在默认模块内");
return null;
}
}
QueryInsaleAcion.java:
package Action;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class QueryInSaleAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("在销售模块内");
return null;
}
}
这里看出来,两个Action都只打印了一句话——在默认模块内还是在销售模块内,当我们在地址栏输入query.do的时候,控制台会输出:
当我们在地址栏加上"/sale"后,控制台会输出:
切换方法1:使用链接切换
用html:link指定module(模块路径)和page(.do 文件路径)名称
<html:link page="/页面" module="/模块名称"></html:link>
如果想要在页面上通过点击链接到达不同的模块,可以选择两种不同的方式,一种是在action里面像地址栏一样的输入具体路径,还有一种是在module里面填写模块名称,代码如下:
p1.jsp
<%@ taglib prefix="html" uri="http://struts.apache.org/tags-html" %>
<%--
Created by IntelliJ IDEA.
User: air
Date: 2019-08-17
Time: 18:33
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>选取模块</title>
</head>
<body>
<html:link action="/query.do">默认模块</html:link><br/>
<html:link action="/query.do" module="/">默认模块</html:link><br/>
<html:link action="/sale/query">销售模块</html:link><br/>
<html:link action="/query" module="/sale">销售模块</html:link>
</body>
</html>
效果如下:
可以看到,两种方法都是在控制台内输出响应的信息。
切换方法2:SwitchAction
在指定模块中声明一个action,此action的type为org.apache.struts.actions.SwitchAction,然后利用:
切换:/actionPath?prefix=/模块名&page=/页面名
<action path="/switch" type="org.apache.struts.actions.Switch Action" />
<html:link action="/switch.do?prefix=/submodule&page=/subJsp.jsp">链接</html:link>
struts-config-sale.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<form-bean name="queryForm" type="ActionForm.QueryForm"></form-bean>
</form-beans>
<action-mappings>
<action path="/query" name="queryForm" type="Action.QueryAction"></action>
<action path="/switch" type="org.apache.struts.actions.SwitchAction"></action>
</action-mappings>
</struts-config>
p1.jsp:
<%@ taglib prefix="html" uri="http://struts.apache.org/tags-html" %>
<%--
Created by IntelliJ IDEA.
User: air
Date: 2019-08-17
Time: 18:33
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>选取模块</title>
</head>
<body>
<html:link action="/query.do">默认模块</html:link><br/>
<html:link action="/query.do" module="/">默认模块</html:link><br/>
<html:link action="/sale/query">销售模块</html:link><br/>
<html:link action="/query" module="/sale">销售模块</html:link><br/>
<%--利用SwitchAction切换--%>
<html:link action="/switch.do?prefix=/sale&page=/query.do">销售模块</html:link>
</body>
</html>
效果和其余两种是一样的,如果想通过这种方式达到默认模块,只需要删除"/sale"即可。
2.插件开发
如果我们希望Struts框架在启动的时候就自动做一些初始化的工作,利用什么方案比较好呢?
传统方法:
- 过滤器(服务器启动时自动运行一次init,以后每一次提交都运行一次doFilter)
新建一个过滤器,并且在web.xml中配置一下:
Filters.Fliter1.java:
package Filters;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "Filter")
public class Filter1 implements Filter {
public void destroy() {
System.out.println("过滤器destroy");
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("过滤器DoFilter");
chain.doFilter(req,resp);
}
public void init(FilterConfig config) throws ServletException {
System.out.println("过滤器启动");
}
}
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>Filter1</filter-name>
<filter-class>Filters.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>config/sale</param-name>
<param-value>/WEB-INF/struts-config-sale.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
然后启动服务器,可以看到服务器在第一次启动的时候,init方法会被调用。每次提交一次请求的时候,DoFliter方法都会被调用一次。但是过滤器的功能太庞大了,Struts一向以小巧灵活著称,所以Struts提供了一个插件的方法,可以实现相同的功能。
- 让Struts启动的时候, 向application内放入一个内容。
一般方法:插件
- 建立一个类,实现org.apache.struts.action.PlugIn接口
- 编写方法,注意Servlet参数,用处很大
- 配置插件:
<plug-in className=" "></plug-in>
PlugIn.plugin1.java:
package PlugIn;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;
import javax.servlet.ServletException;
public class plugin1 implements PlugIn {
@Override
public void destroy() {
System.out.println("插件destroy");
}
@Override
public void init(ActionServlet actionServlet, ModuleConfig moduleConfig) throws ServletException {
System.out.println("插件初始化");
}
}
struts-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<form-bean name="queryForm" type="ActionForm.QueryForm"></form-bean>
</form-beans>
<action-mappings>
<action path="/query" name="queryForm" type="Action.QueryAction"></action>
<action path="/switch" type="org.apache.struts.actions.SwitchAction"></action>
</action-mappings>
<plug-in className="PlugIn.plugin1"></plug-in>
</struts-config>
当我们启动服务器的时候,过滤器初始化,然后插件初始化。
在插件中,可以看到重写的init方法的参数里面有一个ActionServlet,说明插件是可以和Servlet坐一起操作,比如获取Servlet里面的信息。同样,插件也可以获取配置文件中的信息。比如做一个插件,检查某文件的字符编码是什么,就可以利用插件从配置文件里面去查找。
在插件类里面创建一个JavaBean风格的私有成员,然后在web.xml里面配置属性即可,代码如下:
plugin.java:
package PlugIn;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ModuleConfig;
import javax.servlet.ServletException;
public class plugin1 implements PlugIn {
private String value1;
@Override
public void destroy() {
System.out.println("插件destroy");
}
@Override
public void init(ActionServlet actionServlet, ModuleConfig moduleConfig) throws ServletException {
System.out.println("插件初始化");
}
public String getValue1() {
return value1;
}
public void setValue1(String value1) {
this.value1 = value1;
}
}
struts-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<form-bean name="queryForm" type="ActionForm.QueryForm"></form-bean>
</form-beans>
<action-mappings>
<action path="/query" name="queryForm" type="Action.QueryAction"></action>
<action path="/switch" type="org.apache.struts.actions.SwitchAction"></action>
</action-mappings>
<plug-in className="PlugIn.plugin1">
<set-property property="value1" value="welcome"></set-property>
</plug-in>
</struts-config>
注意:在配置文件中可以通过设置属性来影响插件的行为
插件和过滤器的区别
插件:只是负责初始化
过滤器:功能齐全
二者都会在服务器启动的时候自动初始化,如果是一个较大的系统,这样会耗费大量资源,二者没有什么区别。过滤器的初始化顺序高于插件的初始化顺序,过滤器的功能比较多,插件无法做到过滤的功能,过滤器无法访问Struts里面的功能,而插件可以。
看上去过滤器的功能的确比较齐全,所以需要一个新的扩展来专门负责过滤功能,和插件联合起来使用,大致上可以比得上过滤器的功能。
3.扩展
如果希望在表单处理之前,让Struts做一些事情,相当于一个过滤功能,应该用什么方法?
传统方法:过滤器,但是缺陷是不可以访问struts对象。
而RequestProcessor类可以实现这种拓展:
Struts运行时,提交到ActionServlet,底层实际上是调用RequestProcessor来完成工作的:
那我们知道了这个底层的知识后,我们先一步继承RequestProcessor类,然后重写方法,就相当于可以在Struts被提交前做一些操作
- 建立一个类,继承org.apache.struts.action.RequestProcessor
- 编写方法,注意需要重写方法processPreprocess,注意返回值
- 配置控制器:
<controller processorClass="extendsevlet.CProcessor"></controller>
具体代码如下:
Filters.Filter2.java:
package Filters;
import org.apache.struts.action.RequestProcessor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Filter2 extends RequestProcessor {
@Override
protected boolean processPreprocess(HttpServletRequest request, HttpServletResponse response) {
System.out.println("Filter2过滤(扩展RequestProcessor)");
return true;//true表示请求继续向下传递进行处理,false表示不处理请求。
}
}
这个时候系统还是不认识这个扩展组件的,所以需要在struts-config.xml里面进行配置:
struts-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"
"http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<form-bean name="queryForm" type="ActionForm.QueryForm"></form-bean>
</form-beans>
<action-mappings>
<action path="/query" name="queryForm" type="Action.QueryAction"></action>
<action path="/switch" type="org.apache.struts.actions.SwitchAction"></action>
</action-mappings>
<controller processorClass="Filters.Filter2"></controller>
<plug-in className="PlugIn.plugin1">
<set-property property="value1" value="welcome"></set-property>
</plug-in>
</struts-config>
值得一提的是,过滤器可以接受get、post的请求,而扩展的过滤组件则只能接受表单的提交,所以过滤器的功能还是强大一些,当然也可以在扩展组件里面设置其他属性达到想要的目的。
但是扩展组件的优势也是有的,通过上面重写的processPreprocess方法,可以利用this.调用Struts对象,这是过滤器做不到的。
扩展RequestProcessor:默认情况下,只能过滤表单提交
4.小结
插件和扩展的结合使用,虽然比不上过滤器的强大功能,但是也能够勉强满足需求,在项目开发的实际过程中,我们可以根据需求去选择不同的方法。