Spring MVC
Struts2 简介
控制层框架
-
来自Apache基金会的软件: http://struts.apache.org
-
Struts2 与 Struts1 完全没有关系
-
Struts2 的前身是 WebWorks
-
Spring MVC\Struts2\Struts1 都是 MVC 模式的Web框架
-
MVC是非常流行的 用户界面设计模式。
-
MVC是3层架构中的表现层。
-
配置Struts2
Struts2核心jar包
配置步骤:
-
下载Struts2的jar包
-
从struts.apache.org 下载
-
解压缩
-
将*.jar复制到 /WEB-INF/lib 文件夹
-
-
使用maven下载
-
使用Eclipse内嵌搜索,搜索到 struts2-core 的“坐标(xml)”,保存pom.xml
-
使用 maven.tedu.cn/nexus (maven.aliyun.com/nextus) 在线搜索, 搜索到 struts2-core 的“坐标(xml)”,保存pom.xml
-
-
-
配置主控制器
-
控制器类
-
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
-
在struts-core-xxxx.jar 包中
-
-
编辑文件 web.xml(部署描述文件)
-
filter
-
filter-mapping
-
-
-
添加struts的配置文件
-
位置:package中(classpath中)
-
文件名:struts.xml, struts的filter会自动按照文件名struts.xml找到这个文件, 文件名不能错!!!
-
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!-- Struts2 MVC 配置 -->
<!-- filter 会自动找package中的struts.xml -->
<filter>
<filter-name>mvc</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>mvc</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
空白 struts.xml
<?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>
</struts>
Hello World!步骤
-
修改配置文件struts.xml 添加web请求的处理路径
-
-
namespace="/test" 表示处理一级路径 /test
-
extends="struts-default" 继承现有struts的参数
-
name="hello"处理2级路径 /test/hello.action
-
class="com.tedu.HelloAction"
-
在处理url请求时候执行HelloAction 的 execute() 方法,
-
execute方法一定有String返回值,常见的值有 "success" "error"
-
-
-
/WEB-INF/msg.jsp
-
与action方法的返回值配合, 表示返回 “success”时候,转发到msg.jsp页面,msg.jsp作为用户看的视图。
-
-
-
添加类 com.tedu.HelloAction
-
包含 String execute()
-
方法中 return "success";
-
-
添加 /WEB-INF/msg.jsp
struts.xml 文件参考:
<?xml version="1.0" encoding="UTF-8"?>
<!-- struts.xml -->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- 用于配置请求路径与控制器的匹配关系 -->
<!-- /test 请求被这个包进行处理 -->
<package name="test" namespace="/test"
extends="struts-default">
<!-- 请求/test/hello.action时候
执行HelloAction的execute()方法 -->
<action name="hello"
class="com.tedu.HelloAction">
<!-- execute方法返回success
时候,转发到msg.jsp-->
<result name="success">
/WEB-INF/msg.jsp
</result>
</action>
</package>
</struts>
HelloAction.java :
package com.tedu;
public class HelloAction {
/**
* 方法名必须是execute
*/
public String execute(){
System.out.println("Hello World!");
//返回值时候success
return "success";
}
}
msg.jsp:
<%@ page language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
由控制器向页面传递消息
-
在控制器中添加属性,并且为属性添加get方法
-
在控制器方法中向属性赋值
-
在JSP页面上使用 EL 表达式读取属性值
-
EL表达式实际上执行属性的get方法,如果没有get方法就无法获取属性值。
-
案例:
HelloAction
public class HelloAction {
private String message;
public String getMessage() {
return message;
}
/**
* 方法名必须是execute
*/
public String execute(){
message = "Hi";
System.out.println("Hello World!");
//返回值时候success
return "success";
}
}
msg.jsp
<%@ page language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello</title>
</head>
<body>
<h1>Hello World!</h1>
<!-- 自动调用getMessage方法获取信息 -->
<h2>${message}</h2>
</body>
</html>
从页面向控制器传递值
有两种方式可以从页面向控制器传输数据:
-
基本Bean属性传递方式
-
域模型属性传递方式
1. 基本属性传递方式
-
在控制器中声明与html表单项 name 属性一致的Bean属性。
-
添加Bean属性的getxxx setxxx方法。
-
Struts会在接受请求时候,自动将表单属性值注入到 Bean 属性中
代码:
Login.jsp
<%@ page language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c"
uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<!-- /WEB-INF/login.jsp -->
<html>
<head>
<meta charset="utf-8">
<title>登录</title>
</head>
<body>
<h1>登录</h1>
<c:url var="url"
value="/user/login.action"/>
<form action="${url}" method="post">
<div>
<label>用户名:</label>
<input type="text"
name="username"/>
</div>
<div>
<label>密码</label>
<input type="password"
name="password">
</div>
<div>
<input type="submit" value="登录">
</div>
</form>
</body>
</html>
LoginAction.java
public class LoginAction {
private String username;
private String password;
//getxxx setxxx 称为:Bean 属性访问方法
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String execute(){
System.out.println(
username + "," + password);
//完整的登录逻辑...待续
return "success";
}
}
ok.jsp
<%@ page language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>成功消息</title>
</head>
<body>
<h1>欢迎 ${username}</h1>
</body>
</html>
struts.xml (片段)
<package name="user"
namespace="/user"
extends="struts-default">
<!--显示登录页面/user/loginForm.action-->
<action name="loginForm">
<result>/WEB-INF/login.jsp</result>
</action>
<!-- 处理登录请求/user/login.action -->
<action name="login"
class="com.tedu.LoginAction">
<result name="success">
/WEB-INF/ok.jsp
</result>
</action>
</package>
2. 域模型属性传递方式
利用域模型打包传递表单数据, 优点: 1. 可以便捷的处理表单输入项目很多 2. 特别是在表单被项目重用时候,显得更加方便。
原理:
步骤: 1. 创建域模型对象 User - 添加属性 id 和 pwd - 添加bean属性访问方法 2. 在控制器中添加User属性user和get set方法 3. 在表单中的输入项目name属性值为:user.id
代码:
User.java
public class User implements Serializable{
private String id;
private String pwd;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User [id=" + id + ", pwd=" + pwd + "]";
}
}
Login2Action.java
public class Login2Action {
private User user;
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return user;
}
public String execute(){
System.out.println(user);
//其他登录逻辑
return "success";
}
}
login2.jsp (片段)
<h1>登录</h1>
<c:url var="url"
value="/user/login2.action"/>
<form action="${url}" method="post">
<div>
<label>用户名:</label>
<input type="text" name="user.id"/>
</div>
<div>
<label>密码</label>
<input type="password" name="user.pwd">
</div>
<div>
<input type="submit" value="登录">
</div>
</form>
struts.xml(片段)
<!-- 显示 login2.jsp -->
<action name="login2Form">
<result>/WEB-INF/login2.jsp</result>
</action>
<action name="login2"
class="com.tedu.Login2Action">
<result name="success">
/WEB-INF/ok.jsp;
</result>
</action>
ServletContextListener
Servlet
Servlet:在服务器上运行的处理HTTP请求的程序片段,不是完整程序。只能在Web容器环境中执行。Web容器已经开发好,只需要添加程序片Servlet,就可以完成Web开发。
ServletContext 是什么?
Context:上下文,特指运行环境
ServletContext: 就是指Servlet的当前运行环境,如:Tomcat环境。提供了获取环境信息的方法。
ServletContextListener
Servlet环境有创建-运行-销毁的过程,也就是Servlet上下文的生命周期。
ServletContextListener: 可以用于监听 Servlet环境(上下文)的创建和销毁。 - contextInitialized(): ServletContext初始化以后执行 - contextDestroyed(): ServletContext销毁以后执行
用途: 用在系统数据初始化,系统环境初始化。比如:Spring容器环境初始化就是利用ServletContextListener接口实现的。
Struts2
Spring + Struts2
Struts2 提供了 spring 整合插件 struts2-spring-plugin.jar
只要将这个插件添加到/WEB-INF/lib 文件夹中,就会自动将spring整合到Struts2. 整合以后Struts2 的Action对象将由Spring容器创建
1. 手工整合
-
分别到Spring和Struts2网站下载jar包
-
将jar包复制到/WEB-INF/lib 文件夹中
-
修改web.xml文件添加Spring容器初始化监听器
-
添加Spring配置文件。
提示: 这个整合过程过于繁琐,请同学自行实验,正是这个整合过程非常繁琐,才能体现Maven这种自动化工具的优点。
2. 利用Maven整合
-
创建Maven项目,导入Struts2组件,并且配置struts.xml和web.xml
-
<dependency>
-
<groupId>org.apache.struts</groupId>
-
<artifactId>struts2-core</artifactId>
-
<version>2.3.8</version>
-
</dependency>
-
配置struts.xml和web.xml 请参考day01.html
-
-
找到struts2-spring组件坐标添加到Struts2项目的pom.xml,然后保存
-
<dependency>
-
<groupId>org.apache.struts</groupId>
-
<artifactId>struts2-spring-plugin</artifactId>
-
<version>2.3.8</version>
-
</dependency>
-
注意:插件版本必须与 Struts2 的版本必须一致!!!
-
Maven会自动导入插件依赖的Spring包。这是Maven最便捷的特点。
-
-
配置web.xml,利用Spring提供的监听器在Web容器启动时候初始化Spring容器。
-
<listener>
-
<listener-class>
-
org.springframework.web.context.ContextLoaderListener
-
</listener-class>
-
</listener>
-
<context-param>
-
<param-name>contextConfigLocation</param-name>
-
<param-value>classpath:spring-*.xml</param-value>
-
</context-param>
-
其中context-param用于指定Spring配置文件的存储位置
-
-
创建Spring配置文件: spring-context.xml
-
注意这个配置文件要与 Spring版本配合,版本不能错误。
-
-
启动容器进行测试。
参考代码:
pom.xml(片段):
<dependencies>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.3.24</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>2.3.24</version>
</dependency>
</dependencies>
web.xml 片段:
<!-- 配置 Listener 用于初始化Spring容器 -->
<!-- 在Web容器启动时候自动初始化Spring容器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 配置Spring配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-*.xml</param-value>
</context-param>
<!-- Struts2 主控制器配置 -->
<filter>
<filter-name>mvc</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>mvc</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
struts.xml:
<?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>
</struts>
spring-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
</beans>
部署到Web容器测试配置结果...
3. 编写测试案例测试整合结果
-
在Spring配置文件中添加组件扫描
-
添加控制器类,并且在类上添加注解
-
在Struts2 配置文件中添加控制配置,其中class属性引用Spring的Bean ID
-
添加测试用的视图JSP
-
测试
spring-context.xml (片段):
<context:component-scan base-package="com.tedu"/>
HelloAction.class
@Controller
@Scope("prototype") //必须是多例避免线程安全问题
public class HelloAction {
@Resource
private DemoService demoService;
private String message;
public String getMessage(){
return message;
}
public String execute(){
message = demoService.hello();
return "success";
}
}
DemoService.java
@Service
public class DemoService {
public String hello(){
return "Hello World!";
}
}
msg.jsp:
<%@ page language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>
struts.xml (局部):
<package name="demo" namespace="/demo"
extends="struts-default">
<!-- 在有了Spring plugin 以后,action
的class属性就可以使用Spring组件的ID了 -->
<action name="hello"
class="demoAction">
<result name="success">
/WEB-INF/msg.jsp
</result>
</action>
</package>
Result 常用类型
Struts2 支持多种Result类型,其中常用的有: 1. dispatcher 转发 2. redirectAction 重定向到 其他Action 3. redirect 重定向到 其他URL 4. stream 流:用于处理图片或者下载 5. json:用于处理ajax请求
转发类型是在Struts的主配置文件中定义 struts-default.xml json: 在struts2-json-plugin 插件中定义
1. dispatcher 转发
是默认的Result, 也是最常用的类型。
2. redirectAction 重定向到 其他Action
用于处理重定向结果: 详细语法请参考API手册 org.apache.struts2.dispatcher.ServletActionRedirectResult
语法:
<result type="redirectAction">
hello
</result>
或者:
<result type="redirectAction">
<param name="actionName">
hello
</param>
</result>
其中:<param name="actionName"> 是可以省略的
案例:
<action name="test">
<result type="redirectAction">
<param name="actionName">
hello
</param>
</result>
</action>
<action name="test1">
<result type="redirectAction">
hello
</result>
</action>
测试:
请求: http://localhost:8080/demo/test
重定向到:http://localhost:8080/demo/hello.action
请求: http://localhost:8080/demo/test1
重定向到:http://localhost:8080/demo/hello.action
3. redirect 重定向到 其他URL
用于处理重定向结果: 详细语法请参考API手册 org.apache.struts2.dispatcher.ServletRedirectResult
语法:
<result type="redirect">
<param name="location">http://doc.tedu.cn</param>
</result>
或者:
<result type="redirect">
http://doc.tedu.cn
</result>
提示: <param name="location"> 是可以省略的
案例:
<action name="test2">
<result type="redirect">
http://doc.tedu.cn
</result>
</action>
<action name="test3">
<result type="redirect">
<param name="location">http://doc.tedu.cn</param>
</result>
</action>
测试:
请求: http://localhost:8080/demo/test2
重定向到:http://doc.tedu.cn
请求: http://localhost:8080/demo/test3
重定向到:http://doc.tedu.cn
Result 的 name 值不仅仅可以是success,还可以是 任何的值:
案例:
@Controller
@Scope("prototype")
public class SwitchAction {
int num;
public void setNum(int num) {
this.num = num;
}
public String doSwitch(){
return Integer.toString(num);
}
}
struts.xml:
<action name="sw"
class="switchAction"
method="doSwitch">
<result name="1">
/WEB-INF/msg.jsp
</result>
<result name="2" type="redirect">
http://doc.tedu.cn
</result>
<result name="3" type="redirect">
http://tmooc.cn
</result>
<result name="4" type="redirectAction">
hello
</result>
</action>
测试:
请求: http://localhost:8080/demo/sw?num=1
转发到:/WEB-INF/msg.jsp
请求: http://localhost:8080/demo/sw?num=2
重定向到:http://doc.tedu.cn
请求: http://localhost:8080/demo/sw?num=3
重定向到:http://tmooc.cn
请求: http://localhost:8080/demo/sw?num=4
重定向到:http://localhost:8080/demo/hello.action
4. stream 流:用于处理图片或者下载
stream result用于处理图片或者下载,具体语法请参考: org.apache.struts2.dispatcher.StreamResult
关键语法:
<result name="success" type="stream">
<param name="contentType">image/jpeg</param>
<param name="inputName">imageStream</param>
<param name="contentDisposition">attachment;filename="document.pdf"</param>
<param name="bufferSize">1024</param>
</result>
说明: - contentType: 定义媒体类型: image/png 等 - inputName: 必须是一个inputStream类型的流,用于获取发送到客户端的字节数据。如果是图片就是图片编码以后的字节流。 - contentDisposition: 可选参数,如果使用就可以强制下载保存 - bufferSize:可选参数,指定缓存区大小
动态图片处理:
原图片:
处理后:
案例:
@Controller
@Scope("prototype")
public class ImageAction {
private InputStream image;
public InputStream getImage() {
return image;
}
private String name;
public void setName(String name) {
this.name = name;
}
public String card() throws Exception{
//读取图片
//在 包(package)中读取文件
InputStream in =
getClass().getClassLoader()
.getResourceAsStream("1.jpg");
BufferedImage img = ImageIO.read(in);
in.close();
Graphics2D g=img.createGraphics();
g.setRenderingHint(
RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.setFont(new Font("微软雅黑",
Font.BOLD, 20));
g.drawString("“"+name+"我在这里等你...”",
5, 40);
ByteArrayOutputStream out=
new ByteArrayOutputStream();
ImageIO.write(img, "png", out);
out.close();
byte[] data=out.toByteArray();
image=new ByteArrayInputStream(data);
return "success";
}
}
struts.xml:
<action name="card"
class="imageAction"
method="card">
<result name="success"
type="stream">
<param name="contentType">
image/png
</param>
<param name="inputName">
image
</param>
<!--
<param name="contentDisposition">
attachment;filename="hello.png"
</param> -->
</result>
</action>
测试:
请求: http://localhost:8080/demo/card?name=李鸿鹤
结果:
5. json:用于处理ajax请求
json 不是struts默认的result类型,需要使用一个插件来支持这个类型,具体手册:org.apache.struts2.json.JSONResult
用两种使用方式: 1. 将Action的全部属性发送到客户端 - <result name="success" type="json"></result> 2. 将Action的一个属性发送到客户端(最常用) -<result name="success"type="json"> - <param name="root">value</param> - </result> - 其中value是Action的属性名 - 可以将value类型定义为集合,这样就可以将对各数据发送到客户端了。
提示:json返回结果必须使用 struts2-json-plugin 插件支持,必须先导入json插件。
案例1: 返回Action的全部属性:
pom.xml (局部): 导入struts2-json-plugin 插件
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-json-plugin</artifactId>
<version>2.3.8</version>
</dependency>
JsonAction.java:
@Controller
public class JsonAction {
private int id;
public int getId() {
return id;
}
private String message;
public String getMessage() {
return message;
}
public String execute(){
id = 100;
message="Hello!";
return "success";
}
}
struts.xml(局部):
<!-- json-default 来自struts2-json-plugin.jar -->
<package name="jsondemo" namespace="/json" extends="json-default">
<action name="demo" class="jsonAction">
<result name="success" type="json">
</result>
</action>
</package>
测试(JsonAction全部属性值):
请求:/json/demo.action
结果:
{"id":100;"message":"Hello!"}
案例2: 将Action的一个属性发送到客户端:
JsonAction.java:
public class JsonAction {
private int id;
public int getId() {
return id;
}
private String message;
public String getMessage() {
return message;
}
//用于保存,向用户发送的JSON数据
private Map<String, Object> value =
new HashMap<String, Object>();
public Map<String, Object> getValue() {
return value;
}
public String execute(){
value.put("name", "Tom");
value.put("age", 100);
value.put("message", "你吃了吗?");
value.put("error", "吃到吐!");
//....
id = 100;
message="Hello!";
return "success";
}
}
struts.xml(局部):
<package name="jsondemo" namespace="/json" extends="json-default">
<action name="demo" class="jsonAction">
<result name="success" type="json">
<!-- value是JsonAction中需要向客户端发送的数据 -->
<param name="root">value</param>
</result>
</action>
</package>
测试:
请求:/json/demo.action
结果:
{"name":"Tom","message":"你吃了吗?","error":"吃到吐!","age":100}
拦截器
Struts2 也提供了拦截器功能,Struts2的很多默认功能也是通过其内部的拦截器实现的。
拦截器原理:
使用拦截器:
DemoInterceptor.java:
public class DemoInterceptor implements Interceptor {
public void destroy() {
}
public void init() {
}
public String intercept(ActionInvocation in) throws Exception {
System.out.println("开始拦截");
//执行被拦截的 Action
in.invoke();
System.out.println("结束拦截");
return null;
}
}
struts.xml(局部):
<!-- 引入拦截器 -->
<interceptors>
<interceptor name="demo"
class="com.tedu.web.DemoInterceptor"/>
</interceptors>
<action name="hello"
class="helloAction">
<!-- 声明当前Action被demo拦截 -->
<interceptor-ref name="demo"/>
<result name="success">
/WEB-INF/msg.jsp
</result>
</action>
利用拦截器处理异常:
创建拦截器类:
public class ExceptionInterceptor
extends AbstractInterceptor{
public String intercept(
ActionInvocation invocation)
throws Exception {
try {
String val=invocation.invoke();
System.out.println("正常");
return val;
} catch (Exception e) {
e.printStackTrace();
JsonResult result=new JsonResult(e);
Object action = invocation.getAction();
if(action instanceof JsonAction){
((JsonAction)action).setJsonResult(result);
}
System.out.println("错误");
return "error";
}
}
}
继承AbstractInterceptor可以简单代码编写
配置拦截器:
<interceptors >
<interceptor name="exceptionInc"
class="cn.tedu.note.web.ExceptionInterceptor"/>
<interceptor-stack name="expStack">
<interceptor-ref name="basicStack"></interceptor-ref>
<interceptor-ref name="exceptionInc"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="login"
class="cn.tedu.note.action.LoginAction"
method="execute">
<interceptor-ref name="expStack"/>
<result name="success"
type="json">
<param name="root">
jsonResult
</param>
</result>
<result name="error"
type="json">
<param name="root">
jsonResult
</param>
</result>
</action>
提示: 必须带上原有的拦截器栈basicStack,否则原有Struts2的功能失效。
测试: ...
ValueStack
关键点:
-
Struts中用于共享数据的数据结构
-
控制器到JSP页面之间共享数据。
-
拦截器之间,拦截器和控制器JSP之间
-
-
ValueStack结构,两个区域
-
Contents(内容):数据共享区域
-
Context(上下文环境):当前环境信息
-
-
存储数据:
-
Action 本身自动存储在 Contents, 可以直接获取Action
-
可以在Action中调用API向ValueStack中添加数据。
-
ActionContext ctx = ActionContext.getContext();
-
ctx.getValueStack().push(obj);
-
不常见。
-
-
Contents中的数据是顺序查询的
-
Context区域:是一个Map,使用#key读取
-
-
OGNL: 不用代码,使用表达式调用对象的方法。
-
与EL的作用雷同
-
-
Struts2 拦截了EL,底层就是ValueStack
提示: 在Struts2中ValueStack是软件的消息中心的作用。软件的数据和相关环境信息都缓存在这个对象中。其作用于JSP中的 pageContext 类似。
JSP 页面中使用 <s:debug/> 标签可以展示 ValueStack 的内容
OGNL 表达式
OGNL 可以在网页 struts 标签中使用,在Struts2中用于读写ValueStack的数据。
-
读取root区域数据
-
从栈顶到栈底逐一搜索 Bean 属性,找到属性就输出
-
-
读写 context 区域使用 #key 的方式查找
-
#session.loginName
-
提示:OGNL与ValueStack配合可以从控制器向页面传递数据。
ValueStack与EL
Struts2 中的拦截了EL表达式,使其从ValueStack中获取数据,也就是说使用EL就可以很好的访问ValueStack.
案例:
DemoAction.java
@Controller
public class DemoAction {
String message;
public String getMessage() {
return message;
}
public String test(){
ActionContext context =
ActionContext.getContext();
ValueStack stack=context.getValueStack();
Person p = new Person(
1, "Jerry", "Hello Jerry");
//将数据添加到值栈中
stack.push(p);
context.getSession()
.put("loginName", "Robin");
message = "demo";
System.out.println(
"Demo Action test()");
return "success";
}
}
Person.class
public class Person {
int id;
String pname;
String message;
public Person() {
}
public Person(int id, String pname, String message) {
super();
this.id = id;
this.pname = pname;
this.message = message;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
struts.xml(局部)
<package name="test"
namespace="/test"
extends="json-default">
<action name="demo"
class="demoAction"
method="test">
<result name="success">
/WEB-INF/msg.jsp
</result>
</action>
</package>
msg.jsp
<%@ page language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 引入struts2 标签库 -->
<%@taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>test</h1>
<!-- 利用OGNL表达式读取值栈中的数据 -->
<s:property value="message"/> <br>
<s:property value="#session.loginName"/><br>
<!-- 利用EL表达式读取值栈中的数据 -->
${message} <br>
${loginName}
<!-- s:debug 标签可以输出 ValueStack 中的数据 -->
<s:debug></s:debug>
</body>
</html>
Hibernate (冬眠)
将对象存储到关系型数据库中。将对象与关系数据的行对应起来。 ORM 对象关系映射。只要操作对象就自动操作数据库。
使用Hibernate
步骤:
-
导入包
-
创建配置文件
-
配置数据库连接
-
配置实体对象与表的映射关系。
-
-
创建实体对象。
-
创建 Session
-
调用 Session 的方法
-
CRDU方法——增删改查
-
C 创建 R 寻回(查找)D 删除 U更新
-
### 1. 导入Hibernate的相关包
由于是开源软件,其包的依赖关系不够完善,有的Hibernate 版本在导入以后会出现 ClassNotFound 异常。请尝试更换其他版本。
Hibernate pom.xml 坐标:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.9.Final</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.8.0.GA</version>
</dependency>
2. 导入数据库的驱动程序
JDBC 驱动 pom.xml 坐标
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
</dependency>
-
添加Hibernate主配置文件
hibernate.cfg.xml:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/cloud_note?useUnicode=true&characterEncoding=utf8
</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- 加载映射描述文件 -->
<mapping resource="User.hbm.xml" />
</session-factory>
</hibernate-configuration>
4. 添加Hibernate映射配置文件
User.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.tedu.entity.User"
table="cn_user">
<!-- 定义主键映射 -->
<id name="id" column="cn_user_id"
type="string">
</id>
<!-- 定义非主键映射 -->
<property name="name"
column="cn_user_name"
type="string">
</property>
<property name="password"
column="cn_user_password"
type="string">
</property>
<property name="token"
column="cn_user_token"
type="string">
</property>
<property name="nick"
column="cn_user_nick"
type="string">
</property>
</class>
</hibernate-mapping>
5. 添加实体类
注意:建议有ID的实体类实现 equals 和 hashCode 方法! 使用Eclipse生成即可。
User.java
package com.tedu.entity;
import java.io.Serializable;
public class User implements Serializable{
private String id;
private String name;
private String password;
private String token;
private String nick;
public User() {
}
public User(String id, String name, String password, String token, String nick) {
super();
this.id = id;
this.name = name;
this.password = password;
this.token = token;
this.nick = nick;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getNick() {
return nick;
}
public void setNick(String nick) {
this.nick = nick;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", password=" + password + ", token=" + token + ", nick=" + nick
+ "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
6. 调用Hibernate API 就可以自动生成SQL访问数据库了
@Test
public void test1(){
Configuration cfg = new Configuration();
//读取数据库连接参数
cfg.configure("hibernate.cfg.xml");
SessionFactory factory = cfg.buildSessionFactory();
//获取Session对象
Session session = factory.openSession();
//session 可以自动生成SQL查询DB
String id = "022ada2e14f544dbb49468b7cb6f3d42";
User u=(User)session.get( User.class, id);
System.out.println(u);
session.close();
}
测试CURD方法
案例:
public class TestCase {
SessionFactory factory;
@Before
public void init(){
Configuration cfg=new Configuration();
cfg.configure("hibernate.cfg.xml");
factory=cfg.buildSessionFactory();
}
@Test
@Ignore
public void testGetUser()
throws Exception {
Session session=factory.openSession();
String id="39295a3d-cc9b-42b4-b206-a2e7fab7e77c";
User user=(User)session.get(User.class, id);
System.out.println(user);
//session.save(arg0);//insert
//session.update(arg0);//update
//session.delete(arg0);//delete
}
//@Test
public void testSaveUser(){
Session session = null;
Transaction tx = null;
try {
session = factory.openSession();
tx=session.beginTransaction();
User u = new User("123",
"Andy", "123", "", "Andy");
session.save(u);
User one = (User)session.get(
User.class, "123");
System.out.println(one);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
}
}
@Test
public void testUpdateUser(){
Session session = null;
Transaction tx = null;
try {
session = factory.openSession();
tx=session.beginTransaction();
User u = (User)session.get(
User.class, "123");
System.out.println(u);
//session.evict(u);
u.setName("John");
session.update(u);
u = (User)session.get(
User.class, "123");
System.out.println(u);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
}
}
//@Test
public void testDeleteUser(){
Session session = null;
Transaction tx = null;
try {
session = factory.openSession();
tx=session.beginTransaction();
User u = (User)session.get(
User.class, "123");
System.out.println(u);
u.setName("Wang");
session.delete(u);
u = (User)session.get(
User.class, "123");
System.out.println(u);
//session.evict(arg0);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
}
}
}
对象状态
被Hibernate管理的实体对象有3种状态:
-
临时状态
-
持久状态
-
游离状态
1. 临时状态
刚刚创建的对象或者被删除的对象,数据库中没有对应的记录,这时对象的状态为 临时状态。
调用了 save 或者 saveOrUpdate方法以后, 对象将被保存到数据库中,对象状态将转换为持久状态.
案例 向数据库中添加数据:
@Test
public void testSaveTeacher(){
Session session=openSession();
Transaction t=session.beginTransaction();
t.begin();
Teacher tom = new Teacher("Tom");
System.out.println(tom);
session.save(tom);
System.out.println(tom);
t.commit();
session.close();
}
2. 持久状态
保存以后的对象或者从数据库中获取的对象其状态是持久状态,持久状态下改变对象的数据将生成相应的sql语句,将对象的状态保存到数据库中。
案例,改变对象的属性:
@Test
//更新属性实验
public void testUpdateName(){
Session s = openSession();
Transaction t=s.beginTransaction();
t.begin();
Student stu =
(Student)s.get(Student.class, 1);
System.out.println(stu);
//持久状态:更新对象属性会自动更新数据库
stu.setName("M1");
stu.setName("M1");
stu.setName("Mac");
System.out.println(stu);
t.commit();
s.close();
}
3. 游离状态
对称被从Session的缓存中清理出来对象状态变成游离状态,游离状态对象脱离于数据库的联系,更改对象的属性,不再影响数据库,如果需要将游离状态的对象数据更新到数据库可以调用 update 方法,update方法执行以后,对象又还原回 持久状态,并且将已经更改的属性更新到数据库。
案例:
更新游离更新游离状态对象的属性,不影响数据库的数据
@Test
//游离状态测试
public void testObject(){
Session s = openSession();
Transaction t=s.beginTransaction();
t.begin();
//get获取的对象是持久状态的
Student stu=(Student)s.get(
Student.class, 2);
//从session缓存中将stu踢出,离开
//session对象变成游离状态,与数据库
//脱离联系
System.out.println(stu);
s.clear();//将session缓存的全部对象踢出
//s.evict(stu);//踢出一个对象
//脱离持久状态的对象更新属性不再改变
//数据库的值了
stu.setName("Andy");
System.out.println(stu);
t.commit();
s.close();
}
案例:
将游离状态状态对象的属性更新到数据库:
@Test
public void testUpdate(){
Session s=openSession();
Transaction t=s.beginTransaction();
t.begin();
Student stu=(Student)s.get(
Student.class, 3);
System.out.println(stu);
s.evict(stu);//使stu变成游离状态
stu.setName("Nemo");
System.out.println(stu);
s.update(stu);//update使stu从新返回持久状态
t.commit();
s.close();
}
Spring 与 Hibernate 整合
整合的目的: 将Hibernate的对象交给Spring容器,由Spring容器进行管理。
步骤:
-
导入Hibernate
-
导入数据库驱动
-
数据连接池:DBCP C3P0 阿里
-
-
导入Spring
-
导入Spring-ORM 是Spring整合Hibernate的扩展插件
-
配置Spring
-
配置数据源(连接池)
-
配置Hibernate SessionFactory
-
Hibernate的参数配置进去
-
-
配置 事务管理
-
配置 HibernateTemplate,封装了Hibernate提供CRUD方法
-
-
编写数据访问层(DAO)接口
-
实现DAO
-
注入HibernateTemplate,利用HibernateTemplate实现CRUD
-
-
测试DAO
1. 导入Hibernate
分别导入 Hibernate 和 JDBC Driver 以及 连接池C3p0
提示:连接池可以使用 DBCP C3P0 或者阿里云的 druid
pom.xml:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.9.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1</version>
</dependency>
2. 导入Spring
Spring 并不是最新版本最好,要与Hibernate的版本配合才行。
Spring 与 Hibernate 的版本配合情况,以实际测试结果为准。
pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
3. 导入Spring-ORM 是Spring整合Hibernate的扩展插件
这个插件是Spring提供的, 用于在Spring中整合支持Hibernate。
提示:spring-orm 的版本要与Spring-core的版本一致
pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
4. 配置Spring
利用Spring的配置文件,配置Hibernate 相关组件,将Hibernate交给Spring容器进行管理。
添加Spring配置文件: spring-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
</beans>
配置数据源:
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass"
value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl"
value="jdbc:mysql://localhost:3306/cloud_note" />
<property name="user" value="root"/>
<property name="password" value="123456" />
<property name="maxPoolSize" value="10" />
</bean>
提示:不同厂商提供的数据源参数是有区别的,以相关的手册为准。
配置Hibernate SessionFactory
<!-- 配置Hibernate SessionFactory -->
<!-- 其创建的Bean类型是SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 连接到的数据库 -->
<property name="dataSource"
ref="dataSource" />
<!-- Hibernate 参数 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<!-- 映射文件参数 -->
<property name="mappingLocations">
<list>
<value>classpath:User.hbm.xml</value>
<!--
<value>classpath:Book.hbm.xml</value>
-->
</list>
</property>
</bean>
提示: LocalSessionFactoryBean 是Spring提供的工厂Bean,这个Bean会创建 SesisonFactory对象。
配置 事务管理
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 打开注解驱动的事务管理 -->
<tx:annotation-driven transaction-manager="txManager"/>
提示:利用事务管理器,就可以将Hibernate的事务托管到Spring,利用Spring提供的注解就可以管理事务的开启提交和关闭。可以大大简化编码。
配置 HibernateTemplate,template封装了Hibernate提供CRUD方法,用法比Hibernate Session 更加简便。
<!-- 配置Hibernate 模板Bean -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
开启组件扫描支持:
<context:component-scan base-package="com.tedu"/>
注意:要扫描具体的项目包com.tedu,不要扫描com包!com包包含的子包太多了!!!
5. 编写数据访问层(DAO)接口
编写实体类 User
public class User implements Serializable{
private static final long serialVersionUID = 4406629431472824631L;
private String id;
private String name;
private String password;
private String token;
private String nick;
public User() {
}
public User(String id, String name, String password, String token, String nick) {
this.id = id;
this.name = name;
this.password = password;
this.token = token;
this.nick = nick;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getNick() {
return nick;
}
public void setNick(String nick) {
this.nick = nick;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", password=" + password + ", token=" + token + ", nick=" + nick + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
编写实体类的 DAO 接口,声明实体CRUD方法
public interface UserDao {
void save(User user);
void delete(User user);
void update(User user);
User findById(String id);
List<User> findAll();
User findByName(String name);
}
6. 实现DAO
利用Spring注解注入 hibernateTempalet 对象,就可以非常便捷的实现DAO接口。hibernateTempalet封装了Hibernate提供的CRUD功能。
@Repository("userDao")
@Transactional
public class HibernateUserDao implements UserDao {
@Autowired
private HibernateTemplate hibernateTemplate;
public void save(User user) {
hibernateTemplate.save(user);
}
public void delete(User user) {
hibernateTemplate.delete(user);
}
public void update(User user) {
hibernateTemplate.update(user);
}
@SuppressWarnings("rawtypes")
public User findById(String id) {
String hql = "from User where id=?";
List list = hibernateTemplate.find(hql, id);
if(list.size()==0){
return null;
}else{
return (User)list.get(0);
}
}
@SuppressWarnings("unchecked")
public List<User> findAll() {
String hql = "from User";
List<User> list= hibernateTemplate.find(hql);
return list;
}
@SuppressWarnings("rawtypes")
public User findByName(String name) {
String hql= "from User where name=:name";
List list=hibernateTemplate.findByNamedParam(hql, "name", name);
if(list.isEmpty()){
return null;
}
return (User)list.get(0);
}
}
7. 测试 DAO
导入 JUnit API
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
添加测试类:
public class TestCase {
ApplicationContext ctx;
@Before
public void init(){
ctx=new ClassPathXmlApplicationContext(
"spring-context.xml");
}
@Test
public void testFindByName(){
UserDao dao =
ctx.getBean("userDao", UserDao.class);
User user = dao.findByName("tedu");
System.out.println(user);
}
}
测试! Good Luck!!
Hibernate
ORM 框架:将对象映射存储数据库中的行。
Hibernate: 面向对象,已对象的方式访问数据库,复杂 MyBatis:面向数据库,从数据库角度考虑问题,轻量简单
Spring 与 Hibernate 整合
整合的目的: 将Hibernate的对象交给Spring容器,由Spring容器进行管理。
步骤:
-
导入Hibernate
-
导入数据库驱动
-
数据连接池:DBCP C3P0 阿里
-
-
导入Spring
-
导入Spring-ORM 是Spring整合Hibernate的扩展插件
-
配置Spring
-
配置数据源(连接池)
-
配置Hibernate SessionFactory
-
Hibernate的参数配置进去
-
-
配置 事务管理
-
配置 HibernateTemplate,封装了Hibernate提供CRUD方法
-
-
编写数据访问层(DAO)接口
-
实现DAO
-
注入HibernateTemplate,利用HibernateTemplate实现CRUD
-
-
测试DAO
1. 导入Hibernate
分别导入 Hibernate 和 JDBC Driver 以及 连接池C3p0
提示:连接池可以使用 DBCP C3P0 或者阿里云的 druid
pom.xml:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.9.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1</version>
</dependency>
2. 导入Spring
Spring 并不是最新版本最好,要与Hibernate的版本配合才行。
Spring 与 Hibernate 的版本配合情况,以实际测试结果为准。
pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
3. 导入Spring-ORM 是Spring整合Hibernate的扩展插件
这个插件是Spring提供的, 用于在Spring中整合支持Hibernate。
提示:spring-orm 的版本要与Spring-core的版本一致
pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
4. 配置Spring
利用Spring的配置文件,配置Hibernate 相关组件,将Hibernate交给Spring容器进行管理。
添加Spring配置文件: spring-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
</beans>
配置数据源:
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass"
value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl"
value="jdbc:mysql://localhost:3306/cloud_note" />
<property name="user" value="root"/>
<property name="password" value="123456" />
<property name="maxPoolSize" value="10" />
</bean>
提示:不同厂商提供的数据源参数是有区别的,以相关的手册为准。
配置Hibernate SessionFactory
<!-- 配置Hibernate SessionFactory -->
<!-- 其创建的Bean类型是SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 连接到的数据库 -->
<property name="dataSource"
ref="dataSource" />
<!-- Hibernate 参数 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<!-- 映射文件参数 -->
<property name="mappingLocations">
<list>
<value>classpath:User.hbm.xml</value>
<!--
<value>classpath:Book.hbm.xml</value>
-->
</list>
</property>
</bean>
提示: LocalSessionFactoryBean 是Spring提供的工厂Bean,这个Bean会创建 SesisonFactory对象。
配置 事务管理
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 打开注解驱动的事务管理 -->
<tx:annotation-driven transaction-manager="txManager"/>
提示:利用事务管理器,就可以将Hibernate的事务托管到Spring,利用Spring提供的注解就可以管理事务的开启提交和关闭。可以大大简化编码。
配置 HibernateTemplate,template封装了Hibernate提供CRUD方法,用法比Hibernate Session 更加简便。
<!-- 配置Hibernate 模板Bean -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
开启组件扫描支持:
<context:component-scan base-package="com.tedu"/>
注意:要扫描具体的项目包com.tedu,不要扫描com包!com包包含的子包太多了!!!
5. 编写数据访问层(DAO)接口
编写实体类 User
public class User implements Serializable{
private static final long serialVersionUID = 4406629431472824631L;
private String id;
private String name;
private String password;
private String token;
private String nick;
public User() {
}
public User(String id, String name, String password, String token, String nick) {
this.id = id;
this.name = name;
this.password = password;
this.token = token;
this.nick = nick;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getNick() {
return nick;
}
public void setNick(String nick) {
this.nick = nick;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", password=" + password + ", token=" + token + ", nick=" + nick + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
编写实体类的 DAO 接口,声明实体CRUD方法
public interface UserDao {
void save(User user);
void delete(User user);
void update(User user);
User findById(String id);
List<User> findAll();
User findByName(String name);
}
6. 实现DAO
利用Spring注解注入 hibernateTempalet 对象,就可以非常便捷的实现DAO接口。hibernateTempalet封装了Hibernate提供的CRUD功能。
@Repository("userDao")
@Transactional
public class HibernateUserDao implements UserDao {
@Autowired
private HibernateTemplate hibernateTemplate;
public void save(User user) {
hibernateTemplate.save(user);
}
public void delete(User user) {
hibernateTemplate.delete(user);
}
public void update(User user) {
hibernateTemplate.update(user);
}
@SuppressWarnings("rawtypes")
public User findById(String id) {
String hql = "from User where id=?";
List list = hibernateTemplate.find(hql, id);
if(list.size()==0){
return null;
}else{
return (User)list.get(0);
}
}
@SuppressWarnings("unchecked")
public List<User> findAll() {
String hql = "from User";
List<User> list= hibernateTemplate.find(hql);
return list;
}
@SuppressWarnings("rawtypes")
public User findByName(String name) {
String hql= "from User where name=:name";
List list=hibernateTemplate.findByNamedParam(hql, "name", name);
if(list.isEmpty()){
return null;
}
return (User)list.get(0);
}
}
7. 测试 DAO
导入 JUnit API
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
添加测试类:
public class TestCase {
ApplicationContext ctx;
@Before
public void init(){
ctx=new ClassPathXmlApplicationContext(
"spring-context.xml");
}
@Test
public void testFindByName(){
UserDao dao =
ctx.getBean("userDao", UserDao.class);
User user = dao.findByName("tedu");
System.out.println(user);
}
}
测试! Good Luck!!
添加软件的业务层
步骤:
-
添加业务层接口,定义软件的业务功能
-
可能会根据业务的需要定义业务异常
-
-
实现业务方法
-
业务数据从数据层DAO中获取。
-
需要一些工具方法
-
-
测试业务接口
1. 添加业务层接口
定义软件的业务功能:
public interface UserService {
/**
* 登录功能
* @param username 用户名
* @param password 密码
* @return 登录成功返回用户信息
* @throws NameOrPwdException 登录失败
*/
User login(String username, String password) throws NameOrPwdException;
/**
* 显示全部系统用户
* @return 系统用户列表
*/
List<User> list();
}
定义业务异常:
public class NameOrPwdException extends Exception {
private static final long serialVersionUID = -3976559209959446209L;
public NameOrPwdException() {
}
public NameOrPwdException(String message) {
super(message);
}
public NameOrPwdException(Throwable cause) {
super(cause);
}
public NameOrPwdException(String message, Throwable cause) {
super(message, cause);
}
public NameOrPwdException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
2. 实现业务方法
实现业务方法,要点
-
注入数据访问层DAO
-
务必开启事务处理
-
最后对方法的入口参数进行检验,提高软件的健壮性。
UserServiceImpl.java
//在Spring容器中注册Bean userService
@Service("userService")
@Transactional
public class UserServiceImpl
implements UserService{
@Autowired
private UserDao userDao;
@Transactional(readOnly=true)
public User login(
String username, String password)
throws NameOrPwdException {
if(username==null || username.trim().isEmpty()){
throw new NameOrPwdException("用户名不能空");
}
if(username.length()>20){
throw new NameOrPwdException("用户名太长了!");
}
if(password==null || password.trim().isEmpty()){
throw new NameOrPwdException("密码不能为空");
}
User someone = userDao.findByName(username);
if(someone==null){
throw new NameOrPwdException("用户名或密码错误");
}
String pwd=MD5Util.md5(password);
if(someone.getPassword().equals(pwd)){
return someone;
}
throw new NameOrPwdException("用户名或密码错误");
}
@Transactional(readOnly=true)
public List<User> list() {
return userDao.findAll();
}
}
导入编码工具包:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
添加MD5工具类:
public class MD5Util {
public static String md5(String str){
try {
MessageDigest digest =
MessageDigest.getInstance("MD5");
byte[] data=str.getBytes("utf-8");
byte[] md5=digest.digest(data);
return Base64.encodeBase64String(md5);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
3. 测试业务接口
@Test
public void testLogin(){
String username="tedu";
String password="123456";
UserService service = ctx.getBean("userService", UserService.class);
try{
User user = service.login(username, password);
System.out.println(user);
service.login(username, "12");
}catch(Exception e){
e.printStackTrace();
}
}
整合Struts2 + Spring + Hibernate
1. 导入相关的包
导入Struts2
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.3.24</version>
</dependency>
导入Struts2-spring 插件
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>2.3.24</version>
</dependency>
导入struts2-json 插件
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-json-plugin</artifactId>
<version>2.3.24</version>
</dependency>
添加struts2 配置文件 struts.xml
<?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>
</struts>
2. 封装JSON返回值类
Result.java
public class Result<T> implements Serializable {
public static final int SUCCESS=0;
public static final int ERROR=1;
private int state=SUCCESS;
private String message = "";
private T data;
public Result() {
}
public Result(Exception e){
state = ERROR;
message=e.getMessage();
}
public Result(T data){
state = SUCCESS;
message = "SUCCESS";
this.data = data;
}
public Result(int state, String message){
this.state = state;
this.message = message;
}
public Result(String message){
state = SUCCESS;
this.message = message;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
@Override
public String toString() {
return "Result [state=" + state + ", message=" + message + ", data=" + data + "]";
}
}
Action基础类
public abstract class BaseAction
extends ActionSupport
implements Serializable, RequestAware,
SessionAware, ApplicationAware{
protected Map<String, Object> request;
protected Map<String, Object> session;
protected Map<String, Object> application;
public Map<String, Object> getRequest() {
return request;
}
public void setRequest(Map<String, Object> request) {
this.request = request;
}
public Map<String, Object> getSession() {
return session;
}
public void setSession(Map<String, Object> session) {
this.session = session;
}
public Map<String, Object> getApplication() {
return application;
}
public void setApplication(Map<String, Object> application) {
this.application = application;
}
@Autowired
protected UserService userService;
/**
* Json 返回值
*/
protected Result result;
public Result getResult() {
return result;
}
}
3. 实现用户登录功能
定义UserAction 类
@Controller
@Scope("prototype")
public class UserAction extends BaseAction{
//接收用户输入参数
private String username;
private String password;
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
/**
* 登录 Action
*/
public String login(){
try {
User loginUser=userService.login( username, password);
session.put("loginUser", loginUser);
//成功返回登录用户信息
result = new Result<User>(loginUser);
} catch (Exception e) {
e.printStackTrace();
//失败
result = new Result(e);
}
return SUCCESS;
}
}
在struts.xml 中添加Action配置
<package name="user" namespace="/user" extends="json-default">
<action name="login" class="userAction" method="login">
<result name="success" type="json">
<param name="root">result</param>
</result>
</action>
</package>
4. 部署到Tomcat,测试。
5. 实现用户列表功能
导入JSTL
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
添加控制器方法
UserAction.java
private List<User> list;
public List<User> getList() {
return list;
}
public String list(){
try{
list = userService.list();
return SUCCESS;
}catch(Exception e){
e.printStackTrace();
return ERROR;
}
}
添加显示界面JSP
list-user.jsp
<%@ page language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c"
uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户列表</title>
</head>
<body>
<h1>用户列表</h1>
<table>
<tr>
<th>编号</th><th>姓名</th>
</tr>
<c:forEach var="user" items="${list}">
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
添加错误处理页面:
error.jsp
<%@ page language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c"
uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ERROR</title>
</head>
<body>
<h1>有错误了!</h1>
</body>
</html>
添加控制器配置:
struts.xml
<action name="list" class="userAction" method="list">
<result name="success">/WEB-INF/list-user.jsp</result>
<result name="error">/WEB-INF/error.jsp</result>
</action>