1. Struts2 与 Servlet
- 封装 Servlet 的大部分功能,Struts2 是 Servlet 的上层
- Struts2 能做的 Servlet 都能做,反之不行
- Struts2 框架提供了 action,服务器资源增添了 action
- Struts2 在 web.xml 中配置过滤器管理 action
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_3_1.xsd"
version="3.1">
<filter>
<filter-name>struts2</filter-name>
<!--struts2框架提供的核心类过滤器,拿到参数,封装对象-->
<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>-->
<filter-mapping>
<filter-name>struts2</filter-name>
<!--通过 .action -->
<url-pattern>*.action</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>struts2</filter-name>
<!--通过 .jsp -->
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
</web-app>
public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {}
- struts2 框架核心类 StrutsPrepareAndExecuteFilter 实现 Servlet 提供的 Filter 接口
- web.xml 中 <filter-mapping> 目前只允许通过 .action 和 .jsp 后缀的链接
jar 包 链接:http://pan.baidu.com/s/1nvkLAR3 密码:vze1
2. 拦截器
- 拦截访问 action 的请求
- 给这个 action 加入新的丰富功能(上传、参数自动接收、类型自动转换等等)
- 拦截之后,在 intercept 函数 调用 invoke 方法 才真正启动 action
MyInterceptor.java
package com.shuai.web.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
/**
* Created by shuai
* on 2017/8/21.
*/
public class MyInterceptor implements Interceptor {
@Override
public void destroy() {
System.out.println("MyInterceptor destroy...");
}
@Override
public void init() {
System.out.println("MyInterceptor init...");
}
@Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
System.out.println("before...");
String s = actionInvocation.invoke(); // 真正调用action方法 显示toIndex方法中的打印
System.out.println("after...");
return s;
}
}
struts.xml 路径固定,放在 src 下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="cms-package" extends="struts-default">
<interceptors>
<interceptor name="auth" class="com.shuai.web.interceptor.MyInterceptor"></interceptor>
<!--拦截器栈-->
<interceptor-stack name="cmsAuthStack">
<interceptor-ref name="auth"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<global-results>
<result name="toLogin">
/WEB-INF/jsp/login.jsp
</result>
</global-results>
</package>
</struts>
IndexAction.java 在 @Action 注解中加上拦截器
package com.shuai.web.action;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.InterceptorRef;
import org.apache.struts2.convention.annotation.Result;
// 继承 ActionSupport
public class IndexAction extends ActionSupport {
@Action(value = "/toIndex",
results = {@Result(location = "/index.jsp")}, // 默认的SUCCESS,不用指明name
// 配置拦截器,可以拦下页面,做一些处理再显示
interceptorRefs = {@InterceptorRef("cmsAuthStack")}
)
public String toIndex() {
System.out.println("in index...");
return SUCCESS; // Action 接口中 String SUCCESS = "success";
}
}
3. 前端浏览器与后端数据库的交互过程 - 分层开发
Browser:前端页面点击超链接,跳转到 Action 链接;
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主页</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="frameworks/jquery-2.1.4/jquery.min.js"></script>
<script src="js/index.js"></script>
</head>
<body style="margin-left: 10px">
<h1>Ah! We are here</h1>
<ul>
<li><a class="ff" href="javascript:void(0);">显示用户信息</a></li>
<li><a class="ff" href="javascript:void(0);">添加用户信息</a></li>
</ul>
<div class="below"></div>
</body>
</html>
通过 jQuery 的 load 方法实现在 index.jsp 页面中异步加载其他 jsp 页面
index.js
$(function () {
// class选择器
$(".ff").click(function () {
console.log("in ff...");
switch ($(this).text()) {
case "显示用户信息":
// 异步请求 Ajax
// load 方法内部方式实现了 Ajax 在同一个页面的 div 中加载另一个页面
// 选中 below 这个 div 显示 toShowUser.action 对应页面的内容
$(".below").load("toShowUser.action?parentDir=jsp&specifyUrl=showUser.jsp");
break;
case "添加用户信息":
// 同上
$(".below").load("toAddUser.action?parentDir=jsp&specifyUrl=addUser.jsp");
break;
default:
break;
}
});
});
Action:每个 Action 对应 UserAction 类中的一个函数,比如 toShowUser()
,函数内调用 service 接口实现特定功能,比如 service.findAllUsers()
;
UserAction 类中的 toShowUser 函数
@Action(value = "/toShowUser", results = {
@Result(location = "/WEB-INF/jsp/showUser.jsp"),
@Result(name = ERROR, location = "/index.jsp", type = "redirectAction")
})
public String toShowUser() throws ServiceException {
System.out.println("show user...");
List<User> list = service.findAllUsers(); // service 接口
requestMap.put("list", list); // 通过UserAction类实现RequestAware接口传值
return SUCCESS; // Action 接口 String SUCCESS = "success";
}
- @Action 注解中 @Result 默认的是 SUCCESS,不用指明,但是 ERROR 要指明
- SUCCESS = String "success"
Service:与 Service 接口同时存在一个 Service 实现类 UserServiceImpl
,该实现类调用 UserDao 的方法完成与数据库的交互;
UserServiceImpl 类实现 service 接口方法
package com.shuai.service;
import com.shuai.bean.User;
import com.shuai.common.ServiceException;
import com.shuai.dao.UserDao;
import java.util.List;
// UserService 的实现类
public class UserServiceImpl implements UserService {
private UserDao dao = new UserDao();
@Override
public void registerUser(User user) throws ServiceException {
User u = dao.findUserByName(user.getName()); // 查找用户 调用 UserDao 方法
if (u != null) {
throw new ServiceException("user exist!");
} else {
dao.saveUser(user); // 存入数据库 调用 UserDao 方法
}
}
@Override
public List<User> findAllUsers() throws ServiceException {
return dao.findAllUsers(); // 查找所有用户 调用 UserDao 方法
}
}
dao:定义了与数据库交互的方法,通过 Hibernate 实现;
UserDao 类
package com.shuai.dao;
import com.shuai.bean.User;
import com.shuai.common.HibernateSessionFactory;
import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import java.util.List;
/**
* Created by shuai
* on 2017/8/21.
*/
public class UserDao {
// 保存用户
public void saveUser(User user) {
Session session = HibernateSessionFactory.getSession();
Transaction ts = session.beginTransaction();
session.save(user); // 事物内容
ts.commit();
}
// 查询用户
public User findUserByName(String name) {
Session session = HibernateSessionFactory.getSession();
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.add(Restrictions.eq("name", name)).list();
if (list.size() == 0) {
return null;
} else {
return list.get(0);
}
}
// 查询所有用户
public List<User> findAllUsers() {
Session session = HibernateSessionFactory.getSession();
SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM TBL_USER");
sqlQuery.addEntity(User.class); // hibernate.cfg文件注册了映射类
return sqlQuery.list();
}
}
db:通过 hibernate.cfg.xml
文件配置好,就可以前后端交互了。
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.username">briup</property>
<property name="connection.password">briup</property>
<property name="connection.url">
jdbc:oracle:thin:@172.20.10.2:1521:XE
</property>
<property name="connection.driver_class">
oracle.jdbc.driver.OracleDriver
</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!--数据库方言-->
<property name="dialect">
org.hibernate.dialect.OracleDialect
</property>
<!--映射类-->
<mapping class="com.shuai.bean.User"/>
</session-factory>
</hibernate-configuration>
4. 添加用户信息到数据库
addUser.jsp
可以用 form 表单
<h1>addUser</h1>
<form action="toSaveUser.action" method="post">
用户:<input type="text" name="user.name"><br>
密码:<input type="password" name="user.password"><br>
<input type="submit" value="提交">
</form>
也可以用超链接
<h1>addUser</h1>
用户: <input class="na" type="text" name="user.name"><br>
密码: <input class="pwd" type="password" name="user.password"><br><br>
<a id="sb" class="btn btn-success" href="javascript:void(0);"
style="width: 80px; margin-left: 70px">提交</a>
提交按钮对应的 href 是 index.js 中的跳转到 toSaveUser.action 操作
$(function () {
// id选择器
$("#sb").click(function () {
console.log("in sb...");
console.log($(".na").val() + " " + $(".pwd").val());
// js对象
var user = {};
user['user.name'] = $(".na").val();
user['user.password'] = $(".pwd").val();
console.log(user);
// 传给 toSaveUser.action 页面在前端输入的 User
$.post("toSaveUser.action", user, function () {
console.log("发送成功");
})
});
});
UserAction 类中的 toSaveUser 函数对应 toSaveUser.action
//保存用户
@Action(value = "/toSaveUser", results = {
@Result(location = "/index.jsp"),
@Result(name = ERROR, location = "/WEB-INF/jsp/addUser.jsp")
})
public String toSaveUser() {
System.out.println("save user...");
System.out.println("username: " + user.getName());
System.out.println("password: " + user.getPassword());
// $.post("toSaveUser.action", user,..) 接收 user
try {
service.registerUser(user); // 存入数据库
System.out.println("用户存入数据库...");
return SUCCESS;
} catch (ServiceException e) {
e.printStackTrace();
return ERROR;
}
}
toSaveUser 函数调用 Service 接口的 registerUser 方法
UserServiceImpl (Service 的实现类)
package com.shuai.service;
import com.shuai.bean.User;
import com.shuai.common.ServiceException;
import com.shuai.dao.UserDao;
import java.util.List;
// UserService 的实现类
public class UserServiceImpl implements UserService {
private UserDao dao = new UserDao();
@Override
public void registerUser(User user) throws ServiceException {
User u = dao.findUserByName(user.getName());
if (u != null) {
throw new ServiceException("user exist!");
} else {
dao.saveUser(user); // 存入数据库
}
}
@Override
public List<User> findAllUsers() throws ServiceException {
return dao.findAllUsers();
}
}
registerUser 函数调用 UserDao 的 findUserByName 和 saveUser 方法
package com.shuai.dao;
import com.shuai.bean.User;
import com.shuai.common.HibernateSessionFactory;
import org.hibernate.Criteria;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import java.util.List;
/**
* Created by shuai
* on 2017/8/21.
*/
public class UserDao {
// 保存用户
public void saveUser(User user) {
Session session = HibernateSessionFactory.getSession();
Transaction ts = session.beginTransaction();
session.save(user); // 事物内容
ts.commit();
}
// 查询用户
public User findUserByName(String name) {
Session session = HibernateSessionFactory.getSession();
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.add(Restrictions.eq("name", name)).list();
if (list.size() == 0) {
return null;
} else {
return list.get(0); // 如果找到了,第一个元素就是
}
}
}
这样就可以把前端 addUser.jsp 中输入的 User 存入数据库。
5. 显示用户信息
操作顺序 和 添加用户信息 一样
index.jsp 主页面点进超链接进入 toShowUser.action
UserAction 类中 toShowUser.action
@Action(value = "/toShowUser", results = {
@Result(location = "/WEB-INF/jsp/showUser.jsp"), // 可以这样指定location路径
@Result(name = ERROR, location = "/index.jsp", type = "redirectAction")
})
public String toShowUser() throws ServiceException {
System.out.println("show user...");
List<User> list = service.findAllUsers();
requestMap.put("list", list); // 通过UserAction类实现RequestAware接口传值
return SUCCESS;
}
UserServiceImpl (Service实现类)的 findAllUsers 方法
@Override
public List<User> findAllUsers() throws ServiceException {
return dao.findAllUsers();
}
UserDao 类的 findAllUsers 方法
// 查询所有用户
public List<User> findAllUsers() {
Session session = HibernateSessionFactory.getSession();
SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM TBL_USER");
sqlQuery.addEntity(User.class); // hibernate.cfg文件注册了映射类
return sqlQuery.list();
}
执行数据库查询,返回 list
showUser.jsp 显示表内容
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>showUser</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body>
<h1>showUser</h1>
<table class="table table-striped table-bordered" style="width: 50%">
<thead>
<tr>
<th>username</th>
<th>password</th>
</tr>
</thead>
<tbody>
<%--显示传入的list--%>
<c:forEach items="${list}" var="v">
<tr>
<td> ${v.name}</td>
<td> ${v.password}</td>
</tr>
</c:forEach>
</tbody>
</table>
</body>
</html>