一、自定义一个Struts框架
1、MVC模式包括
Model:模型
View:视图
Control:控制器
2、传统mvc开发总结
① 跳转代码写死,不灵活
② 每次都去写servlet,要web.xml中配置servlet!
3、自定义一个Struts框架
① 配置文件mystruts.xml
<?xml version="1.0" encoding="UTF-8"?>
<mystruts>
<package>
<!-- 配置请求路径,与处理action类的关系,处理方法 -->
<action name="login" class="cn.itcast.framework.action.LoginAction" method="login">
<result name="loginSuccess" type="redirect">/index.jsp</result>
<result name="loginFaild">/login.jsp</result>
</action>
<action name="register" class="cn.itcast.framework.action.RegisterAction" method="register">
<result name="registerSuccess">/login</result>
<result name="registerFaild">/login</result>
</action>
</package>
</mystruts>
② ActionServlet.java
/**
* 核心控制器,此项目只有这一个servlet
* 1. 拦截所有的*.action为后缀的请求
* 2. 请求:http://localhost:8080/mystruts/login.action
* http://localhost:8080/mystruts/register.action
*/
public class ActionServlet extends HttpServlet{
private ActionMappingManager actionMappingManager;
// 只执行一次,第一次访问时候执行 (希望启动时候执行)
@Override
public void init() throws ServletException {
System.out.println("1111111111111111ActionServlet.init()");
actionMappingManager = new ActionMappingManager();
}
// http://localhost:8080/mystruts/login.action
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
try {
// 1. 获取请求uri, 得到请求路径名称 【login】
String uri = request.getRequestURI();
// 得到 login
String actionName=uri.substring(uri.lastIndexOf("/")+1, uri.indexOf(".action"));
// 2. 根据路径名称,读取配置文件,得到类的全名 【cn..action.LoginAction】
ActionMapping actionMapping = actionMappingManager.getActionMapping(actionName);
String className = actionMapping.getClassName();
// 当前请求的处理方法 【method="login"】
String method = actionMapping.getMethod();
// 3. 通过反射:创建对象,调用方法;获取方法返回的标记
Class<?> clazz = Class.forName(className);
Object obj = clazz.newInstance(); //LoginAction loginAction = new LoginAction();
Method m = clazz.getDeclaredMethod(method, HttpServletRequest.class,HttpServletResponse.class );
// 调用方法返回的标记
String returnFlag = (String) m.invoke(obj, request, response);
// 4. 拿到标记,读取配置文件得到标记对应的页面、跳转类型
Result result = actionMapping.getResults().get(returnFlag);
// 类型
String type = result.getType();
// 页面
String page = result.getPage();
// 跳转
if ("redirect".equals(type)) {
response.sendRedirect(request.getContextPath() + page);
} else {
request.getRequestDispatcher(page).forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
③ Result.java、ActionMapping.java、ActionMappingManager.java
/**
* 封装结果视图
* <result name="success" type="redirect">/index.jsp</result>
*/
public class Result {
// 跳转的结果标记
private String name;
// 跳转类型,默认为转发;"redirect"为重定向
private String type;
// 跳转的页面
private String page;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
}
/**
* 封装action节点
* <action name="login" class="cn.itcast.framework.action.LoginAction" method="login">
* <result name="success" type="redirect">/index.jsp</result>
* <result name="loginFaild">/login.jsp</result>
* </action>
*/
public class ActionMapping {
// 请求路径名称
private String name;
// 处理aciton类的全名
private String className;
// 处理方法
private String method;
// 结果视图集合
private Map<String,Result> results;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public Map<String, Result> getResults() {
return results;
}
public void setResults(Map<String, Result> results) {
this.results = results;
}
}
/**
* 加载配置文件, 封装所有的整个mystruts.xml
*/
public class ActionMappingManager {
// 保存action的集合
private Map<String,ActionMapping> allActions ;
public ActionMappingManager(){
allActions = new HashMap<String,ActionMapping>();
// 初始化
this.init();
}
/**
* 根据请求路径名称,返回Action的映射对象
* @param actionName 当前请求路径
* @return 返回配置文件中代表action节点的AcitonMapping对象
*/
public ActionMapping getActionMapping(String actionName) {
if (actionName == null) {
throw new RuntimeException("传入参数有误,请查看mystruts.xml配置的路径。");
}
ActionMapping actionMapping = allActions.get(actionName);
if (actionMapping == null) {
throw new RuntimeException("路径在mystruts.xml中找不到,请检查");
}
return actionMapping;
}
// 初始化allActions集合
private void init() {
/********DOM4J读取配置文件***********/
try {
// 1. 得到解析器
SAXReader reader = new SAXReader();
// 得到src/mystruts.xml 文件流
InputStream inStream = this.getClass().getResourceAsStream("/mystruts.xml");
// 2. 加载文件
Document doc = reader.read(inStream);
// 3. 获取根
Element root = doc.getRootElement();
// 4. 得到package节点
Element ele_package = root.element("package");
// 5. 得到package节点下所有的action子节点
List<Element> listAction = ele_package.elements("action");
// 6.遍历 ,封装
for (Element ele_action : listAction) {
// 6.1 封装一个ActionMapping对象
ActionMapping actionMapping = new ActionMapping();
actionMapping.setName(ele_action.attributeValue("name"));
actionMapping.setClassName(ele_action.attributeValue("class"));
actionMapping.setMethod(ele_action.attributeValue("method"));
// 6.2 封装当前aciton节点下所有的结果视图
Map<String,Result> results = new HashMap<String, Result>();
// 得到当前action节点下所有的result子节点
Iterator<Element> it = ele_action.elementIterator("result");
while (it.hasNext()) {
// 当前迭代的每一个元素都是 <result></result>
Element ele_result = it.next();
// 封装对象
Result res = new Result();
res.setName(ele_result.attributeValue("name"));
res.setType(ele_result.attributeValue("type"));
res.setPage(ele_result.getTextTrim());
// 添加到集合
results.put(res.getName(), res);
}
// 设置到actionMapping中
actionMapping.setResults(results);
// 6.x actionMapping添加到map集合
allActions.put(actionMapping.getName(), actionMapping);
}
} catch (Exception e) {
throw new RuntimeException("启动时候初始化错误",e);
}
}
}
④ LoginAction.java、RegisterAction.java
/**
* Action表示动作类 1. 一个servlet对应一个action 2. action中负责处理具体的请求
*/
public class LoginAction {
public Object execute(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
return null;
}
/**
* 处理登陆请求
*/
public Object login(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Object uri = null;
// 1. 获取请求数据,封装
String name = request.getParameter("name");
String pwd = request.getParameter("pwd");
User user = new User();
user.setName(name);
user.setPwd(pwd);
// 2. 调用Service
UserService userService = new UserService();
User userInfo = userService.login(user);
// 3. 跳转
if (userInfo == null) {
// 登陆失败
// request.getRequestDispatcher("/login.jsp").forward(request,response);
// uri = request.getRequestDispatcher("/login.jsp");
uri = "loginFaild"; // loginFaild = /login.jsp
} else {
// 登陆成功
request.getSession().setAttribute("userInfo", userInfo);
// 首页
// response.sendRedirect(request.getContextPath() + "/index.jsp");
// uri = "/index.jsp";
uri = "loginSuccess"; // loginSuccess = /index.jsp
}
return uri;
}
}
public class RegisterAction {
public Object register(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
Object uri;
// 1. 获取请求数据,封装
String name = request.getParameter("name");
String pwd = request.getParameter("pwd");
User user = new User();
user.setName(name);
user.setPwd(pwd);
// 2. 调用Service
UserService userService = new UserService();
userService.register(user);
// 3. 跳转
// request.getRequestDispatcher("/login.jsp").forward(request, response);
//uri = request.getRequestDispatcher("/login.jsp");
return "registerSuccess"; //返回注册的标记; registerSuccess = /login.jsp
}
}
二、基于MVC模式的应用框架之Struts
1、Struts就是基于mvc模式的框架!
struts其实也是servlet封装,提高开发效率!
2、Struts开发步骤
① web项目,引入struts - jar包8个jar文件
② web.xml中,引入struts的核心功能配置过滤器
<!-- 引入struts核心过滤器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意:如果引用其他拦截器一定要放在Struts拦截器上面
③ 开发action
// 开发action: 处理请求
public class HelloAction extends ActionSupport {
// 处理请求
public String execute() throws Exception {
System.out.println("访问到了action,正在处理请求");
System.out.println("调用service");
return "success";
}
}
④ 配置actionsrc/struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="xxxx" extends="struts-default">
<action name="hello" class="cn.itcast.action.HelloAction" method="execute">
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
三、Struts框架学习
1、框架学习概述
SSH框架在mvc模式的的位置作用:
2、框架:
软件中的框架,是一种半成品; 我们项目开发需要在框架的基础上进行!
因为框架已经实现了一些功能,这样就可以提高开发效率!
3、Struts2框架
① Struts1最早的一种基于mvc模式的框架
② Struts2 是在Struts1的基础上,融合了xwork的功能
也可以说,Struts2 = struts1 + xwork
4、Struts2框架预先实现了一些功能:
① 请求数据自动封装
② 文件上传的功能
③ 对国际化功能的简化
④ 数据效验功能
……
5、Struts2(版本: 2.3)开发流程【重点】
① 引入jar文件
◆ commons-fileupload-1.2.2.jar 【文件上传相关包】
◆ commons-io-2.0.1.jar
◆ struts2-core-2.3.4.1.jar 【struts2核心功能包】
◆ xwork-core-2.3.4.1.jar 【Xwork核心包】
◆ ognl-3.0.5.jar 【Ognl表达式功能支持表】
◆ commons-lang3-3.1.jar 【struts对java.lang包的扩展】
◆ freemarker-2.3.19.jar 【struts的标签模板库jar文件】
◆ javassist-3.11.0.GA.jar 【struts对字节码的处理相关jar】
② 配置web.xml
Tomcat启动 > 加载自身web.xml > 加载所有项目的web.xml
通过在项目的web.xml中引入过滤器,Struts的核心功能的初始化,通过过滤器完成( filter 【init/ doFilter/ destroy】)
<!-- 引入struts核心过滤器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
struts2-core-2.3.4.1.jar
StrutsPrepareAndExecuteFilter 即为核心过滤器
注意:使用的struts的版本不同,核心过滤器类是不一样的!
③ 开发Action
注意:
◆ action类,也叫做动作类,一般继承ActionSupport类,即处理请求的类 (struts中的action类取代之前的servlet)
◆ action中的业务方法,处理具体的请求( 必须返回String、方法不能有参数)
public class HelloAction extends ActionSupport {
// 处理请求
public String execute() throws Exception {}
}
④ 配置struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="xxxx" extends="struts-default">
<action name="hello" class="cn.itcast.action.HelloAction" method="execute">
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
6、Struts2执行流程
① 服务器启动:
◆ 加载项目web.xml
◆ 创建Struts核心过滤器对象, 执行filter > init()
struts-default.xml
:核心功能的初始化
struts-plugin.xml
:struts相关插件
struts.xml
:用户编写的配置文件
② 访问:
◆ 用户访问Action, 服务器根据访问路径名称,找对应的aciton配置,创建action对象
◆ 执行默认拦截器栈中定义的18个拦截器
◆ 执行action的业务处理方法
7、struts-default.xml
详解
① 目录:struts2-core-2.3.4.1.jar/ struts-default.xml
② 内容:
◆ bean节点指定struts在运行的时候创建的对象类型
◆ 指定struts-default包 【用户写的package(struts.xml)一样要继承此包 】
package:struts-default
包中定义了:
◇ 跳转的结果类型
dispatcher 转发,不指定默认为转发
redirect 重定向
redirectAction 重定向到action资源
stream (文件下载的时候用)
◇ 定义了所有32个拦截器
为了拦截器引用方便,可以通过定义栈的方式引用拦截器,此时如果引用了栈,栈中的拦截器都会被引用!
defaultStack:默认的栈,其中定义默认要执行的18个拦截器(按顺序执行)!
默认执行的拦截器栈、默认执行的action
<default-interceptor-ref name="defaultStack"/>
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
8、拦截器(先睹为快):
拦截器功能与过滤器功能类似。
① 共同点: 都拦截资源!
② 区别 :
◆ 过滤器,拦截器所有资源都可以(/index.jsp/servlet/img/css/js)
◆ 拦截器,只拦截action请求。
◆ 拦截器是struts的概念,只能在struts中用。
◆ 过滤器是servlet的概念,可以在struts项目、servlet项目用。
③ 面试题: 拦截器什么时候执行? (访问/启动) 先执行action类创建,还是先执行拦截器?
答:用户访问时候按顺序执行18个拦截器;先执行Action类的创建,再执行拦截器; 最后拦截器执行完,再执行业务方法。
9、共性问题
① 问题1:Struts.xml配置文件没有提示
◆ 解决a:找到struts-2.0.dtd文件, 拷贝到某个目录(不要用中文目录),让MyEclipse关联到上面dtd文件(windows > preferences > 搜索xml catalog):
配置:
Location:上面配置的dtd目录
Key:-//Apache Software Foundation//DTD Struts Configuration 2.0//EN
◆ 解决b:让机器连接互联网,工具会自动下载dtd文件,缓存到MyEclipse中!
② 问题2
◆ 如果查看struts源码,需要关联源码包文件:struts-2.3.4.1-all
◆ 如果查看xwork源码,需要再单独下载xwork源码jar文件:xwork-core-2.3.4.1-sources
,并再次关联
10、
① package:定义一个包,包的作用:管理action(通常一个业务模块用一个包)
② name:包的名字,包名不能重复
③ extends:当前包继承哪个包,在struts中,包一定要继承struts-default
struts-default是在struts-default.xml中定义的
④ abstract:表示当前包为抽象包,抽象包不能有action的定义,否则运行时会报错
只有当前包被其他包继承时,abstract=true
⑤ namespace:名称空间,默认为“/”,作为路径
⑥ action:配置请求路径与action类的映射关系(name请求路径名称,class请求处理action类全名,method请求处理方法)
⑦ result:name是action处理方法返回值,type是跳转的结果类型,标签体中指定跳转的界面
<struts>
<package name="xxxx" extends="struts-default">
<action name="hello" class="cn.itcast.action.HelloAction" method="execute">
<result name="success">/success.jsp</result>
</action>
</package>
</struts>