后端常用数据持久层模板及框架以及一些工具类模板的配置使用集合
文章目录
- 后端常用数据持久层模板及框架以及一些工具类模板的配置使用集合
- JDBC、c3p0、hibernate配置模板;JDBC模板方法模式、抽象工厂模式封装模板;Spring+hibernate+c3p0配置文件模板;springboot+mybatis配置文件模板;ChStr(解决文本乱码和格式问题)等工具类模板;struts配置模板、正则表达式、文档的上传下载、文档的自动生成(Japidocs的使用)等:
- 1、JDBC、c3p0、hibernate、spring+hibernate+c3p0、springboot+mybatis小结:
- 2、JDBC测试模板(仅测试用):
- 3、配置文件+JdbcUtil+Dao层:
- 4、ConnDB(封装性较JdbcUtil好):
- 5、ChStr类:解决字符串中文乱码问题同时保证显示文本中的回车换行、空格及保证HTML标记的正常输出
- 6、模板方法模式实现JDBC封装
- 7、抽象工厂模式实现JDBC封装(配置文件+反射+简单工厂改造后的抽象工厂实现多数据库访问)
- 8、使用C3P0连接池技术实现数据库连接组件
- 9、(题外话)在进行hibernate之前配置之前,先叙述一下正则表达式的相关内容以及<![CDATA[]]>和转义字符之间的关系解释(hibernate以及struts相关配置都需使用正则表达式):
- 10、hibernate配置(不再需要c3p0.properties文件,直接在hibernate.cfg.xml文件中进行配置):
- hibernate.cfg.xml示例一(搭配c3p0配置及解释):
- hibernate.cfg.xml示例二(hibernate属性配置及解释,mapping资源文件与class之间的对应映射关系):
- HibernateUtil:
- 建立泛型接口IBaseDaoHibernate< T>:
- DaoHibernate< T> implements IBaseDaoHibernate< T>(泛型实现):
- 自动生成mapping:资源文件与class之间的对应映射关系:
- 自动生成后的文件:
- (1)映射文件StudentEntity.hbm.xml:
- (2)StudentEntity:
- (3)当然这里还会在hibernate.cfg.xml中生成资源与类的映射对应关系,这里不再赘述。
- 11、到这里JDBC,c3p0,hibernate的基本配置就基本结束了,我们可以发现配置文件是逐渐增多的,封装也是逐步完善的。通过对底层工具类模板的逐步封装,我们在dao层编写项目逻辑时(对数据库的基本操作)也逐步趋于简洁。
- 12、Spring对上述内容的整合:
- applicationContext.xml(不再需要c3p0.properties文件,属性全部配置在该文件中,同时hibernate.cfg.xml文件也不再需要配置c3p0属性,但是需要一个最初的赋值配置,即db.properties)(在hibernate.cfg.xml文件中也不再需要配置资源与类的映射关系,只需在该文件中配置自动扫描注解方式配置的hibernate类文件等信息即可):
- 当然在配置applicationContext.xml之前还应在web.xml中配置applicationContext.xml位置等,web.xml:
- db.properties:
- hibernate.cfg.xml(无需c3p0配置和资源映射关系配置):
- config文件夹下内容如下:
- 上述config文件夹下还有日志配置log4j.xml(与Struts、hibernate等配置无关):
- 13、题外话(Struts配置与使用):
- config文件夹下struts.xml文件内容:
- config文件夹->struts文件夹下struts-user.xml文件:
- 对于struts还可以进行拦截器配置(例如对文件的上传下载):
- 当然struts配置action也可以通过注解进行配置,不必采用struts-user.xml文件进行配置,直接将对应逻辑(返回值等)通过注解方式写到Action类中,比如CardAction:
- 文件上传下载与Excel、数据表数据之间的转换
- struts还可以配置拦截器,放在Action类的同一个包下,如(一定要注意名字格式):
- 其中UserAction-register-validation.xml配置文件内容如下:
- UserAction(此处userService采用注解配置并通过Spring注入方式直接注入,同时注意struts-action与jsp/html界面的属性名(name)之间的一一对应关系同时注明get、set函数否则将会出现404的错误):
- jsp/html界面(以注册界面register.jsp为例,注意属性名(name)与action之间的一一对应关系):
- 上述Action类包含实体类,这里叙述一下编写模型类(实体类)entity的规范:
- 至此,struts配置以及spring+struts+hibernate配置基本完毕。
- 14、SpringBoot+Mybatis配置:
- 采用Maven方式pom.xml对相关依赖文件进行导入:
- application.yml配置(尤其需要注意格式,例如空格等,也可采用application.properties配置):
- 配置mybatis Mapper文件(放置在资源resources文件夹下):
- controller层接收前端请求进行处理:
- service接收controller层传来的请求进行业务处理(接口与实现imp):
- 编写Dao层接口以期实现数据库访问:
- 编写Mapper映射关系实现真正的数据库操作:
- 实体类补充:
- 注意内容:注意上面的Mapper文件中数据表与实体类之间的映射关系以及Mapper文件与Dao层之间的映射关系(特别注意方法名、传参类型、返回结果、获取变量方式等),还需注意where 1=1条件永真的用处,可参考:[where 1=1有什么用?](https://blog.csdn.net/qq_23994787/article/details/79045768)、[SQL where 1=1的作用](https://www.cnblogs.com/xijin-wu/p/5590010.html),注意#{}与 $ {}的区别,可参考文章:[#{}与 $ {}的区别](https://blog.csdn.net/zouxucong/article/details/52837387)、[#{}与 $ {}的区别](https://blog.csdn.net/a22222259/article/details/90722112)
- 15、题外话(文档的自动生成、Japidocs的使用)
后端常用数据持久层模板及框架以及一些工具类模板的配置使用集合
JDBC、c3p0、hibernate配置模板;JDBC模板方法模式、抽象工厂模式封装模板;Spring+hibernate+c3p0配置文件模板;springboot+mybatis配置文件模板;ChStr(解决文本乱码和格式问题)等工具类模板;struts配置模板、正则表达式、文档的上传下载、文档的自动生成(Japidocs的使用)等:
1、JDBC、c3p0、hibernate、spring+hibernate+c3p0、springboot+mybatis小结:
JDBC配置:
文件配置db.properties(注意文件目录位置和反射加载对比)
c3p0配置:
在使用前首先应建立c3p0的配置文件(在项目src目录下)
hibernate配置:
在使用前首先应建立hibernate.cfg.xml配置文件(在项目src目录下)
hibernate配置(不再需要c3p0.properties文件,直接在hibernate.cfg.xml文件中进行配置)
spring注解配置(spring+hibernate+c3p0):
applicationContext.xml(不再需要c3p0.properties文件,属性全部配置在该文件中,同时hibernate.cfg.xml文件也不再需要配置c3p0属性,但是需要一个最初的赋值配置,即db.properties)(在hibernate.cfg.xml文件中也不再需要配置资源与类的映射Mapper关系,只需在该文件中配置自动扫描注解方式配置的hibernate类文件等信息即可。
当然在配置applicationContext.xml之前还应在web.xml中配置applicationContext.xml位置等。
springboot+mybatis配置:
在pom.xml引入相关依赖并在application.yml或者application.properties文件中配置好相关内容,在dao层编写接口,资源mapper文件编写具体对数据库的实现操作即可(注意mapper.xml文件与dao层之间的映射关系与数据表和实体间的映射关系以及SQL语句书写格式等问题)
2、JDBC测试模板(仅测试用):
package test_jdbc;
/*
* 数据库驱动
DBC :是接口 驱动是接口的实现 没有驱动无法完成连接数据库
每个数据库厂商定义自己的驱动接口,用来连接数据库
JDBC:为java开发者提供的的操作数据库的接口
实现:
1.注册驱动
告知JVM使用的是哪一个数据库的驱动 Class.forName("驱动");
2.获得连接
使用JDBC中的类,完成对数据库的连接 Connection con = DriverManager.getConnection(url, username, password);
3.获得语句执行平台
通过连接对象获取对SQL语句的执行者对象 Statement statement = con.createStatement();
4.执行sql语句
使用执行者对象,向数据库执行SQL语句
ResultSet result = statement .executeQuery(sql);/int result = statement .executeUpdate(sql); .....
获取到数据库的执行后的结果
5.处理结果
6.释放资源 close() result.close(); statement.close(); con.close();
*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBC {
public static void main(String[] args) {
//声明Connection对象
Connection con;
//驱动程序名
String driver = "com.mysql.cj.jdbc.Driver";
/*
* Loading class `com.mysql.jdbc.Driver'. This is deprecated.
* The new driver class is `com.mysql.cj.jdbc.Driver'.
* The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
* 加载类“com.mysql.jdbc.Driver”。这是弃用。
* 新的驱动程序类是' com.mysql.cj.jdbc.Driver'。
* 驱动程序是通过SPI自动注册的,手动加载驱动程序类通常是不必要的。
*/
//URL指向要访问的数据库名mydata
String url = "jdbc:mysql://localhost:3306/mysql"
+ "?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
/*
* url里设置一下时区就行了
* java.sql.SQLException: The server time zone value ‘乱码’ is unrecognized or represents more than one time zone.
* You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
*/
//MySQL配置时的用户名
String user = "root";
//MySQL配置时的密码
String password = "123456mjg";
//遍历查询结果集
try {
//加载驱动程序
Class.forName(driver);
//1.getConnection()方法,连接MySQL数据库!!
con = DriverManager.getConnection(url,user,password);
if(!con.isClosed())
System.out.println("Succeeded connecting to the Database!");
//2.创建statement类对象,用来执行SQL语句!!
/**
* statement (Java 执行数据库操作的一个重要接口),Statement 是 Java 执行数据库操作的一个重要接口,
* 用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。Statement对象,用于执行不带参数的简单SQL语句。
* statement 用于执行静态 SQL 语句并返回它所生成结果的对象。
* 在默认情况下,同一时间每个 Statement 对象在只能打开一个 ResultSet 对象。
* 因此,如果读取一个 ResultSet 对象与读取另一个交叉,则这两个对象必须是由不同的 Statement 对象生成的。
* */
Statement statement = con.createStatement();
//要执行的SQL语句
String sql = "select * from jdbc_test";
//3.ResultSet类,用来存放获取的结果集!!
ResultSet rs = statement.executeQuery(sql);
System.out.println("--------------------------------------");
System.out.println("执行结果如下所示:");
System.out.println("------------------------");
System.out.println("学号" + "\t" + "姓名" + "\t" + "性别" + "\t" + "年龄");
System.out.println("--------------------------------------");
String name= null;
String id = null;
String sex = null;
String age = null;
while(rs.next()){
//获取sno这列数据
id = rs.getString("sno");
//获取sname这列数据
name = rs.getString("sname");
//获取sex这列数据
sex = rs.getString("sex");
//获取age这列数据
age = rs.getString("age");
//输出结果
System.out.println(id + "\t" + name + "\t" + sex + "\t" + age);
}
rs.close();
con.close();
} catch(ClassNotFoundException e) {
//数据库驱动类异常处理
System.out.println("Sorry,can`t find the Driver!");
e.printStackTrace();
} catch(SQLException e) {
//数据库连接失败异常处理
e.printStackTrace();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
finally{
System.out.println("数据库数据成功获取!!");
}
}
}
3、配置文件+JdbcUtil+Dao层:
文件配置db.properties:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
username=root
password=sa
JdbcUtil(只建立连接、释放连接):
package util;
import java.sql.*;
import java.util.Properties;
public final class JdbcUtil {
private static String driver ;
private static String url ;
private static String user ;
private static String password ;
private static Properties pr=new Properties();
private JdbcUtil() {}
//设计该工具类的静态初始化器中的代码,该代码在装入类时执行,且只执行一次
static {
try {pr.load(JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties"));
driver=pr.getProperty("driver");
url=pr.getProperty("url");
user=pr.getProperty("username");
password=pr.getProperty("password");
Class.forName(driver);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
//设计获得连接对象的方法getConnection()
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
//设计释放结果集、语句和连接的方法free()
public static void free(ResultSet rs, Statement st, Connection conn) {
try { if (rs != null) rs.close();
} catch (SQLException e) {e.printStackTrace();
} finally {
try { if (st != null) st.close();
} catch (SQLException e) {e.printStackTrace();
} finally {
if (conn != null)
try { conn.close();
} catch (SQLException e) {e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws Exception{
JdbcUtil.getConnection();
}
}
UserDao:
package dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import entity.User;
import util.JdbcUtil;
public class UserDao {
//向数据库中添加用户记录的方法add()
public void add(User user) throws Exception{
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
String sql = "insert into user values (?,?,?) ";
ps = conn.prepareStatement(sql);
ps.setString(1, user.getUserid());
ps.setString(2,user.getUsername());
ps.setString(3,user.getSex());
ps.executeUpdate();
}finally {JdbcUtil.free(null,ps, conn);}
}
//修改数据库用户记录的方法update()
public void update(User user) throws Exception{
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
String sql = "update user set username=?,sex=? where userid=? ";
ps = conn.prepareStatement(sql);
ps.setString(1,user.getUsername());
ps.setString(2,user.getSex());
ps.setString(3, user.getUserid());
ps.executeUpdate();
}finally {JdbcUtil.free(null,ps, conn);}
}
//删除数据库用户记录的方法delete()
public void delete(String userId) throws Exception{
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
String sql = "delete from user where userid=?";
ps = conn.prepareStatement(sql);
ps.setString(1,userId);
ps.executeUpdate();
}finally {JdbcUtil.free( null,ps, conn);}
}
//根据id查询用户的方法findUserById()
public User findUserById(String userId) throws Exception{
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
User user=null;
try {
conn = JdbcUtil.getConnection();
String sql = "select * from user where userid=? ";
ps = conn.prepareStatement(sql);
ps.setString(1, userId);
rs=ps.executeQuery();
if(rs.next()){
user=new User();
user.setUserid(rs.getString(1));
user.setUsername(rs.getString(2));
user.setSex(rs.getString(3));
}
}finally {JdbcUtil.free(rs, ps, conn);}
return user;
}
//查询全部用户的方法QueryAll()
public List<User> QueryAll() throws Exception{
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
List<User> userList=new ArrayList<User>();
try {
conn = JdbcUtil.getConnection();
String sql = "select * from user ";
ps=conn.prepareStatement(sql);
rs=ps.executeQuery();
while(rs.next()){
User user=new User();
user.setUserid(rs.getString(1));
user.setUsername(rs.getString(2));
user.setSex(rs.getString(3));
userList.add(user);
}
}finally {JdbcUtil.free(rs, ps, conn);}
return userList;
}
}
其中User类如下:
package entity;
public class User {
private String userid,username,sex;
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
4、ConnDB(封装性较JdbcUtil好):
package tools;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class ConnDB {
public Connection conn = null; //数据库连接对象
public Statement stmt = null; //Statement对象,用于执行SQL语句
public ResultSet rs = null; //结果集对象
private static String dbClassName = "com.mysql.cj.jdbc.Driver"; //驱动类的类名
private static String dbUrl = "jdbc:mysql://localhost:3306/学生成绩管理系统"
+ "?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";
private static String dbUser = "root";
private static String dbPwd = "123456mjg";
/**
* 功能:创建与数据库的连接
*
* @return
*/
public static Connection getConnection() {
Connection conn = null;// 声明数据库连接对象
try {// 捕捉异常
Class.forName(dbClassName).newInstance();// 装载数据库驱动
conn = DriverManager.getConnection(dbUrl, dbUser, dbPwd);// 获取数据库连接对象
} catch (Exception ee) {// 处理异常
ee.printStackTrace();// 输出异常信息
}
if (conn == null) {
System.err.println("DbConnectionManager.getConnection():" + dbClassName + "\r\n :" + dbUrl + "\r\n "
+ dbUser + "/" + dbPwd);// 输出连接信息,方便调试
}
return conn; // 返回数据库连接对象
}
/**
* 功能:更新数据
*
* @param sql
* @return
*/
public int executeUpdate(String sql) {
int result = 0;// 更新数据的记录条数
try {// 捕捉异常
conn = getConnection();// 获取数据库连接
// 创建用于执行SQL语句的Statement对象
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
result = stmt.executeUpdate(sql);// 执行SQL语句
} catch (SQLException ex) {// 处理异常
result = 0;// 指定更新数据的记录条数为0,表示没有更新数据
ex.printStackTrace();// 输出异常信息
}
try {// 捕捉异常
stmt.close();// 关闭用于执行SQL语句的Statement对象
} catch (SQLException ex1) {// 处理异常
ex1.printStackTrace();// 输出异常信息
}
return result;// 返回更新数据的记录条数
}
/**
* 功能:根据指定的SQL语句查询数据
*
* @param sql
* @return
*/
public ResultSet executeQuery(String sql) {
try {// 捕捉异常
conn = getConnection();// 获取数据库连接
// 创建用于执行SQL语句的Statement对象
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
rs = stmt.executeQuery(sql);// 执行SQL语句
} catch (SQLException ex) {// 处理异常
ex.printStackTrace();// 输出异常信息
}
return rs;// 返回查询结果
}
/**
* 功能:关闭数据库连接
*/
public void close() {
try { // 捕捉异常
if (rs != null) {
rs.close();// 关闭结果集对象
}
if (stmt != null) {
stmt.close(); // 关闭Statement对象
}
if (conn != null) {
conn.close(); // 关闭数据库连接对象
}
} catch (Exception e) {// 处理异常
e.printStackTrace(System.err);// 输出异常信息
}
}
/**
* 功能:测试数据库连接是否成功
* @param args
*/
public static void main(String[] args) {
if (getConnection() != null) {//如果获取到数据库连接
System.out.print("数据库连接成功!");
}
}
/**
* 功能:更新数据后获取生成的自动编号
*
* @param sql
* @return
*/
public int executeUpdate_id(String sql) {
int result = 0;
try {// 捕捉异常
conn = getConnection();// 获取数据库连接
// 创建用于执行SQL语句的Statement对象
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
result = stmt.executeUpdate(sql);// 执行SQL语句
String ID = "select @@IDENTITY as id";// 定义用于获取刚刚生成的自动编号的SQL语句
rs = stmt.executeQuery(ID);// 获取刚刚生成的自动编号
if (rs.next()) {// 如果存在数据
int autoID = rs.getInt("id");// 把获取到的自动编号保存到变量autoID中
result = autoID;
}
} catch (SQLException ex) {// 处理异常
result = 0;
}
return result;// 返回获取结果
}
}
Dao层使用:
package dao;
import java.sql.ResultSet;
import JavaBean.User;
import tools.ConnDB;
public class UserDao {
/**
* 用户验证登陆账号密码
*/
public int user_login(User us) {
int flag = -1;
ConnDB conn = new ConnDB();
try {
String sql = "select * from user where user_login='" + us.getUser_login() + "' and user_pwd='"
+ us.getUser_pwd() + "'";
ResultSet rs = conn.executeQuery(sql);
while (rs.next()) {
flag = 1;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
conn.close();
}
return flag;
}
/**
* 用户注册
*/
public int user_register(User us) {
int flag = -1;
ConnDB conn = new ConnDB();
try {
String sql = "select * from user where user_login='" + us.getUser_login() + "'";
ResultSet rs = conn.executeQuery(sql);
// 结果集不为空,则该账户已被注册
while (rs.next()) {
return flag;
}
// 结果集为空,给账户未被注册
String sql1 = "insert into user (user_login,user_pwd,user_name) values ( '" + us.getUser_login() + "','"
+ us.getUser_pwd() + "','" + us.getUser_name() + "')";
flag = conn.executeUpdate(sql1);
} catch (Exception e) {
e.printStackTrace();
} finally {
conn.close();
}
return flag;
}
/**
* 管理员把用户和用户所有名片记录删除
*/
public int user_delete(String user_login) {
int flag = -1;
ConnDB conn = new ConnDB();
try {
String sql = "delete from user where user_login='" + user_login + "'";
String sql1 = "delete from card where card_login='" + user_login + "'";
String sql2 = "delete from recycle where card_login='" + user_login + "'";
conn.executeUpdate(sql);
conn.executeUpdate(sql1);
conn.executeUpdate(sql2);
flag = 1;
} catch (Exception e) {
e.printStackTrace();
} finally {
conn.close();
}
return flag;
}
}
5、ChStr类:解决字符串中文乱码问题同时保证显示文本中的回车换行、空格及保证HTML标记的正常输出
package tools;
public class ChStr {
/**
* 功能:解决中文乱码问题
*
* @param str
* @return
*/
public String chStr(String str) {
if (str == null) { // 当变量str为null时
str = ""; // 将变量str赋值为空
} else {
try {// 捕捉异常
str = (new String(str.getBytes("iso-8859-1"), "UTF-8")).trim();// 将字符串转换为UTF-8编码
} catch (Exception e) {// 处理异常
e.printStackTrace(System.err); // 输出异常信息
}
}
return str; // 返回转换后的变量str
}
/**
* 功能:显示文本中的回车换行、空格及保证HTML标记的正常输出
*
* @param str1
* @return
*/
public String convertStr(String str1) {
if (str1 == null) {
str1 = "";
} else {
try {
str1 = str1.replaceAll("<", "<");// 替换字符串中的"<"和">"字符,保证HTML标记的正常输出
str1 = str1.replaceAll(">", ">");
str1 = str1.replaceAll(" ", " ");
str1 = str1.replaceAll("\r\n", "<br>");
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
return str1;
}
}
6、模板方法模式实现JDBC封装
7、抽象工厂模式实现JDBC封装(配置文件+反射+简单工厂改造后的抽象工厂实现多数据库访问)
抽象工厂模式实现JDBC封装(配置文件+反射+简单工厂改造后的抽象工厂实现多数据库访问)
8、使用C3P0连接池技术实现数据库连接组件
在使用前首先应建立c3p0的配置文件(在项目src目录下):
c3p0.properties:
c3p0.user=root
c3p0.password=123456
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/card
c3p0.initPoolSize=5
c3p0.maxPoolSize=10
#driverClassName=com.mysql.jdbc.Driver
#url=jdbc:mysql://localhost:3306/card
#username=root
#password=123456
#initialSize=10
#maxActive=50
#maxIdle=20
#minIdle=5
#maxWait=60000
#connectionProperties=useUnicode=true;characterEncoding=UTF-8;autoReconnect=true
#defaultAutoCommit=true
#defaultReadOnly=
#defaultTransactionIsolation=READ_COMMITTED
JdbcPoolUtils:
//该类使用C3P0连接池技术实现数据库连接组件
package com.edu.db_util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JdbcPoolUtils {
private static DataSource dataSource = new ComboPooledDataSource();
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void close(ResultSet rs, Statement pstmt, Connection con)
throws SQLException {
try {
if (rs != null)
rs.close();
} finally {
try {
if (pstmt != null)
pstmt.close();
} finally {
if (con != null)
con.close();
}
}
}
public static int dbCUD(String sql, Object... params) {
Connection con = null;
PreparedStatement pstmt = null;
int row = 0;
try {
con = JdbcPoolUtils.getConnection();
pstmt = con.prepareStatement(sql);
if (params != null) {
for (int i = 0; i < params.length; i++) {
pstmt.setObject(i + 1, params[i]);
}
}
row = pstmt.executeUpdate();
JdbcPoolUtils.close(null, pstmt, con);
} catch (SQLException e) {
e.printStackTrace();
}
return row;
}
public static ResultSet query(Connection con, String sql, Object... params) {
PreparedStatement pstmt;
ResultSet rs = null;
try {
pstmt = con.prepareStatement(sql);
if (params != null) {
for (int i = 0; i < params.length; i++) {
pstmt.setObject(i + 1, params[i]);
}
}
rs = pstmt.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return rs;
}
}
DaoJdbc(使用JdbcPoolUtil样例):
package com.edu.dao;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.edu.db_util.JdbcPoolUtils;
import com.edu.model.user.User;
public class DaoJdbc {
public User find(User user) {
Connection con;
String sql = "select id,username,userpassword,userrealname from user where username=? and userpassword=? ";
ResultSet rs = null;
User user2 = null;
String params[] = {user.getUserName(), user.getUserPassword()};
try {
con = JdbcPoolUtils.getConnection();
rs =JdbcPoolUtils.query(con, sql, params);
if (rs.next()) {
user2 = new User();
user2.setUserId(rs.getInt("id"));
user2.setUserName(rs.getString("username"));
user2.setUserPassword(rs.getString("userpassword"));
user2.setUserRealName(rs.getString("userrealname"));
}
JdbcPoolUtils.close(rs, null, con);
} catch (SQLException e) {
e.printStackTrace();
}
return user2;
}
}
建立接口IBaseDao:
package com.edu.dao;
import java.util.List;
public interface IBaseDao<T>{
public int insert(T o); //将对象o,添加到数据库内
public int insertList(List<T> list); //将对象集合,添加到数据库内
public int update(T o); //利用对象o,修改当前记录
public int deleteList(int... ids); //利用id的集合,删除该集合中对应id的记录。
public int delete(T o);// 从数据库中删除一个记录o
public int delete(int id);//利用关键字id 从数据库中删除一个记录
public T findById(int id); //利用id,查找一条记录
public T find(T o); //查找对象o
public List<T> findAll(); //查找所有对象
public List<T> findPage(int pageno,int pagesize); //分页查找所有对象
public List<T> findByCondition(String condition); //查找满足条件的所有对象
/**
* 按条件分页查询记录信息,返回List对象值
* @param pageno:页面号
* @param pagesize:一个页面中显示的记录条数
* @param condition:查询条件
* @param order:降序或者升序排序(按id号)
* @return:返回查询记录集合
*/
public List<T> findPageCondition(int pageno,int pagesize,String condition,String order);//按条件分页查询
public long getRecordCount(String condition);//根据查询条件获取记录 的总条数
}
实现IBaseDao接口并使用JdbcPoolUtil(以UserDao为例):
package com.edu.dao.user;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.edu.dao.IBaseDao;
import com.edu.db_util.JdbcPoolUtils;
import com.edu.model.user.User;
public class UserDao implements IBaseDao<User> {
// 向想数据库中插入一个用户
@Override
public int insert(User user) {
String sql = "insert into user(userName,userPassword,userRealName) values(?,?,?)";
Object params[] = { user.getUserName(), user.getUserPassword(),
user.getUserRealName() };
return JdbcPoolUtils.dbCUD(sql, params);
}
@Override
public int insertList(List<User> list) {
for (User user : list) {
insert(user);
}
return list.size();
}
// 使用对象o修改当前对象
@Override
public int update(User user) {
String sql = "update from user set userName=?,userPassword=?,userRealName=? where id=? ";
Object params[] = { user.getUserName(), user.getUserPassword(),
user.getUserRealName(), user.getUserId() };
return JdbcPoolUtils.dbCUD(sql, params);
}
// 修改用户密码: 修改 对象use的密码为newPasswoed
public int updatePassword(User user, String newPassword) {
String sql = "update from user set userpassword=? where username=? and userpassword=? ";
Object params[] = { newPassword, user.getUserName(),
user.getUserPassword() };
return JdbcPoolUtils.dbCUD(sql, params);
}
@Override
public int delete(int id) {
String sql = "delete from user where id=? ";
Object params[] = { id };
return JdbcPoolUtils.dbCUD(sql, params);
}
@Override
public int deleteList(int... ids) {
for (int id : ids) {
delete(id);
}
return ids.length;
}
// 从数据库中删除一个用户
@Override
public int delete(User user) {
int row = delete(user.getUserId());
return row;
}
@Override
public User findById(int id) {
Connection con;
String sql = "select id,username,userpassword,userrealname from user where id=? ";
ResultSet rs = null;
User user2 = null;
Object params[] = { id };
try {
con = JdbcPoolUtils.getConnection();
rs = JdbcPoolUtils.query(con, sql, params);
if (rs.next()) {
user2 = new User();
user2.setUserId(rs.getInt("id"));
user2.setUserName(rs.getString("username"));
user2.setUserPassword(rs.getString("userpassword"));
user2.setUserRealName(rs.getString("userrealname"));
}
JdbcPoolUtils.close(rs, null, con);
} catch (SQLException e) {
e.printStackTrace();
}
return user2;
}
// 必须的方法:登录时,要从数据库查询舒服存在该用户(提交的是账号、密码)
@Override
public User find(User user) {
Connection con;
String sql = "select id,username,userpassword,userrealname from user where username=? and userpassword=? ";
ResultSet rs = null;
User user2 = null;
Object params[] = { user.getUserName(), user.getUserPassword() };
try {
con = JdbcPoolUtils.getConnection();
rs = JdbcPoolUtils.query(con, sql, params);
if (rs.next()) {
user2 = new User();
user2.setUserId(rs.getInt("id"));
user2.setUserName(rs.getString("username"));
user2.setUserPassword(rs.getString("userpassword"));
user2.setUserRealName(rs.getString("userrealname"));
}
JdbcPoolUtils.close(rs, null, con);
} catch (SQLException e) {
e.printStackTrace();
}
return user2;
}
// 列出所有用户
@Override
public List<User> findAll() {
Connection con;
String sql = "select id,userName,userPassword,userRealName from user ";
ResultSet rs = null;
List<User> users = new ArrayList<User>();
Object params[] = null;
try {
con = JdbcPoolUtils.getConnection();
rs = JdbcPoolUtils.query(con, sql, params);
while (rs.next()) {
User user = new User();
user.setUserId(rs.getInt("id"));
user.setUserName(rs.getString("username"));
user.setUserPassword(rs.getString("userpassword"));
user.setUserRealName("userRealName");
users.add(user);
}
JdbcPoolUtils.close(rs, null, con);
} catch (SQLException e) {
e.printStackTrace();
}
return users;
}
@Override
public List<User> findPage(int pageno, int pagesize) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<User> findByCondition(String condition) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<User> findPageCondition(int pageno, int pagesize,
String condition, String order) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getRecordCount(String condition) {
// TODO Auto-generated method stub
return 0;
}
}
其中User类如下:
package com.edu.model.user;
public class User {
private Integer userId;
private String userName;
private String userPassword;
private String userRealName;
public User() {}
public User(String userName, String userPassword,String userRealName) {
this.userName = userName;
this.userPassword = userPassword;
this.userRealName = userRealName;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserRealName() {
return userRealName;
}
public void setUserRealName(String userRealName) {
this.userRealName = userRealName;
}
}
9、(题外话)在进行hibernate之前配置之前,先叙述一下正则表达式的相关内容以及<![CDATA[]]>和转义字符之间的关系解释(hibernate以及struts相关配置都需使用正则表达式):
正则表达式
CDATA和转义字符
被<![CDATA[]]>这个标记所包含的内容将表示为纯文本,比如<![CDATA[<]]>表示文本内容“<”。
此标记用于xml文档中,我们先来看看使用转义符的情况。我们知道,在xml中,”<”、”>”、”&”等字符是不能直接存入的,否则xml语法检查时会报错,如果想在xml中使用这些符号,必须将其转义为实体,如”<”、”>”、”&”,这样才能保存进xml文档。在使用程序读取的时候,解析器会自动将这些实体转换回”<”、”>”、”&”。
正则表达式使用举例(Java版)(struts拦截器)(java.util.regex.Pattern;类):
这里使用到了java.util.regex.Pattern;类matches方法:
源代码:
package action;
import java.util.regex.Pattern;
import beabs.User;
import beabs.UserDbase;
import com.opensymphony.xwork2.ActionSupport;
public class RegisterAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private User user;
private String userPwd;
public String register() throws Exception {
UserDbase ud=new UserDbase();
if(ud.addUser(user)==1) return "success";
else return "error";
}
public void validate() {
if(user.getUserName()==null ||user.getUserName().length()<=0){
addFieldError("user.userName","用户名不能为空!");
}else{
String f1="[a-zA-Z]\\w*";
if(!Pattern.matches(f1,user.getUserName())){
addFieldError("user.userName","用户名格式不正确!"); }
}
if(user.getUserPwd().length()<=0||user.getUserPwd()==null){
addFieldError("user.userPwd","密码不能为空!");
}else{
if(user.getUserPwd().length()<6){
addFieldError("user.userPwd","密码长度不能小于6!"); }
}
if(userPwd.length()<=0||userPwd==null){
addFieldError("userPwd","确认密码不能为空!");
}else{
if(userPwd.equals(user.getUserPwd())){
addFieldError("userPwd","密码不一致!");
}
}
if(user.getUserEmail().length()<=0||user.getUserEmail()==null){
addFieldError("user.userEmail","邮件地址不能为空!");
}else{
String f2="\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*.\\w+([-.]\\w+)*";
if(!Pattern.matches(f2,user.getUserEmail())){
addFieldError("user.userName","邮箱地址格式不正确!");
}
}
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
}
正则表达式使用举例(XML版)(struts拦截器):见下述struts拦截器部分。
10、hibernate配置(不再需要c3p0.properties文件,直接在hibernate.cfg.xml文件中进行配置):
在使用前首先应建立hibernate.cfg.xml配置文件(在项目src目录下):
hibernate.cfg.xml示例一(搭配c3p0配置及解释):
<!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.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///card</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property>
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="hbm2ddl.auto">update</property>
<property name="show_sql">true</property>
<!--
<property name="hibernate.connection.provider_class">
org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider
</property>
-->
<property name="hibernate.connection.provider_class">
org.hibernate.c3p0.internal.C3P0ConnectionProvider
</property>
<!-- 连接池中JDBC连接的最小数量。Hibernate默认为1 -->
<property name="hibernate.c3p0.min_size">2</property>
<!-- 连接池中JDBC连接的最大数量。Hibernate默认为100 -->
<property name="hibernate.c3p0.max_size">5</property>
<!-- 何时从连接池中移除一个空闲的连接(以秒为单位)时。Hibernate默认为0,永不过期 -->
<property name="hibernate.c3p0.timeout">300</property>
<!-- 被缓存的预编译语句数量。用来提高性能。Hibernate默认为0,缓存不可用 -->
<property name="hibernate.c3p0.max_statements">100</property>
<!-- 一个连接被自动验证前的闲置时间(以秒为单位)。Hibernate默认为0 -->
<property name="hibernate.c3p0.idle_test_period">3000</property>
<mapping resource="com/edu/model/user/User.hbm.xml" />
<mapping resource="com/edu/model/card/Card.hbm.xml" />
</session-factory>
</hibernate-configuration>
hibernate.cfg.xml示例二(hibernate属性配置及解释,mapping资源文件与class之间的对应映射关系):
注意< property name=“connection.url”>
< /property>属性的不同。
配置文件:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">
<![CDATA[jdbc:mysql://localhost:3306/homework?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai]]></property>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<!-- 设定一些其他配置 -->
<!-- 运行时是否打印 SQL -->
<property name="show_sql">true</property>
<!-- 运行时是否格式化 SQL -->
<property name="format_sql">true</property>
<!-- 生成数据表的策略 -->
<property name="hbm2ddl.auto">update</property>
<!-- 设置 Hibernate 的事务隔离级别 -->
<property name="connection.isolation">2</property>
<!-- 删除对象后, 使其 OID 置为 null -->
<property name="use_identifier_rollback">true</property>
<!-- 配置 C3P0 数据源 -->
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="c3p0.acquire_increment">2</property>
<property name="c3p0.idle_test_period">2000</property>
<property name="c3p0.timeout">2000</property>
<property name="c3p0.max_statements">1000</property>
<!-- 设定 JDBC 的 Statement 读取数据的时候每次从数据库中取出的记录条数 -->
<property name="hibernate.jdbc.fetch_size">1000</property>
<!-- 设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小 -->
<!-- 需要关联的 hibernate 映射文件 .hbm.xml -->
<mapping resource="entity_hibernate/PublishEntity.hbm.xml"/>
<mapping class="entity_hibernate.PublishEntity"/>
<mapping resource="entity_hibernate/StudentEntity.hbm.xml"/>
<mapping class="entity_hibernate.StudentEntity"/>
<mapping class="entity_hibernate.SubmitEntity"/>
<mapping resource="entity_hibernate/SubmitEntity.hbm.xml"/>
<mapping resource="entity_hibernate/TeacherEntity.hbm.xml"/>
<mapping class="entity_hibernate.TeacherEntity"/>
<!-- <property name="connection.username"/> -->
<!-- <property name="connection.password"/> -->
<!-- DB schema will be updated if needed -->
<!-- <property name="hibernate.hbm2ddl.auto">update</property> -->
</session-factory>
</hibernate-configuration>
HibernateUtil:
package db_util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public final class HibernateUtil {
private static SessionFactory sessionFactory;
private static ThreadLocal<Session> session = new ThreadLocal<Session>();
private HibernateUtil() {
}
static {
// 第一步:读取Hibernate的配置文件 hibernamte.cfg.xml文件
Configuration configuration = new Configuration().configure();
// 第二步:创建服务注册构建器对象,通过配置对象中加载所有的配置信息
StandardServiceRegistryBuilder regbulider = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties());
// 创建注册服务
ServiceRegistry serviceRegistry = regbulider.build();
// 第三步:创建会话工厂
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
public static Session getThreadLocalSession() {
Session s = (Session) session.get();
if (s == null) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() {
Session s = (Session) session.get();
if (s != null) {
s.close();
session.set(null);
}
}
}
建立泛型接口IBaseDaoHibernate< T>:
package dao;
import java.util.List;
public interface IBaseDaoHibernate<T> {
public int insert(T o); // 将对象o,添加到数据库内
public int insertList(List<T> list); // 将对象集合,添加到数据库内
public int update(T o); // 利用对象o,修改当前记录
public int deleteList(Class<T> c, int... ids); // 利用id的集合,删除该集合中对应id的记录。
public int delete(T o);// 从数据库中删除一个记录o
public int delete(Class<T> c, int id);// 利用关键字id 从数据库中删除一个记录
public T findById(Class<T> c, int id); // 利用id,查找一条记录
public T findOne(String hql, String[] param); // 查询单条记录
public List<T> find(String hql, String[] param); // 按条件查找多条记录
public List<T> findPage(String hql, String[] param, int page, int size); // 分页查找所有对象
public int getCount(String hql, String[] pras);// 返回数据个数
public List<T> findByFields(String hql, String fields[], String condition); //单字段模糊查找满足条件的所有对象
}
DaoHibernate< T> implements IBaseDaoHibernate< T>(泛型实现):
package dao;
import java.util.List;
import db_util.HibernateUtil;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class DaoHibernate<T> implements IBaseDaoHibernate<T> {
@Override
public int insert(T o) {
Session s = null;
Transaction tx = null;
int result = 0;
try {
s = HibernateUtil.getThreadLocalSession();
tx = s.beginTransaction();
s.save(o);
tx.commit();
result=1;
} catch (Exception e) {
if (tx != null) {
tx.rollback();// 事物回滚
}
} finally {
HibernateUtil.closeSession();
}
return result;
}
@Override
public int insertList(List<T> list) {
for (T t : list) {
insert(t);
}
return list.size();
}
@Override
public int update(T o) {
Session s = null;
int result = 0;
Transaction tx = null;
try {
s = HibernateUtil.getThreadLocalSession();
tx = s.beginTransaction();
s.update(o);
tx.commit();
result = 1;
} catch (Exception e) {
if (tx != null) {
tx.rollback();// 事物回滚
}
} finally {
HibernateUtil.closeSession();
}
return result;
}
@Override
public int deleteList(Class<T> c, int... ids) {
for (int id : ids) {
delete(c, id);
}
return ids.length;
}
@Override
public int delete(T o) {
Session s = null;
Transaction tx = null;
int result = 0;
try {
s = HibernateUtil.getThreadLocalSession();
tx = s.beginTransaction();
s.delete(o);
tx.commit();
result = 1;
} catch (Exception e) {
if (tx != null) {
tx.rollback();// 事物回滚
}
} finally {
HibernateUtil.closeSession();
}
return result;
}
@Override
public int delete(Class<T> c, int id) {
Session s = null;
Transaction tx = null;
int result = 0;
try {
s = HibernateUtil.getThreadLocalSession();
tx = s.beginTransaction();
s.delete(s.load(c, id));
tx.commit();
result = 1;
} catch (Exception e) {
if (tx != null) {
tx.rollback();// 事物回滚
}
} finally {
HibernateUtil.closeSession();
}
return result;
}
@SuppressWarnings("unchecked")
@Override
public T findById(Class<T> c, int id) {
Session s = null;
T t = null;
try {
s = HibernateUtil.getThreadLocalSession();
t = (T)s.get(c, id);
} finally {
HibernateUtil.closeSession();
}
return t;
}
@SuppressWarnings("unchecked")
@Override
public T findOne(String hql, String[] param) { // 查询单条记录
T t = null;
Session s = null;
try {
s = HibernateUtil.getThreadLocalSession();
Query query = s.createQuery(hql);
if (param != null) {
for (int i = 0; i < param.length; i++) {
query.setParameter(i, param[i]);
}
}
t = (T) query.uniqueResult();
} finally {
HibernateUtil.closeSession();
}
return t;
}
@SuppressWarnings("unchecked")
@Override
public List<T> find(String hql, String[] param) {
List<T> list = null;
Session s = null;
try {
s = HibernateUtil.getThreadLocalSession();
Query query = s.createQuery(hql);
if (param != null) {
for (int i = 0; i < param.length; i++) {
query.setParameter(i, param[i]);
}
}
list = query.list();
} finally {
HibernateUtil.closeSession();
}
return list;
}
@SuppressWarnings("unchecked")
@Override
public List<T> findPage(String hql, String[] param, int page, int size) { // 分页查找所有对象
List<T> list = null;
Session s = null;
try {
s = HibernateUtil.getThreadLocalSession();
Query query = s.createQuery(hql);
if (param != null) {
for (int i = 0; i < param.length; i++) {
query.setParameter(i, param[i]);
}
}
// 筛选条数
query.setFirstResult((page - 1) * size);
query.setMaxResults(size);
list = query.list();
} finally {
HibernateUtil.closeSession();
}
return list;
}
@Override
public int getCount(String hql, String[] param) {// 返回数据个数
int resu = 0;
Session s = null;
try {
s = HibernateUtil.getThreadLocalSession();
Query q = s.createQuery(hql);
if (param != null) {
for (int i = 0; i < param.length; i++) {
q.setString(i, param[i]);
}
}
resu = Integer.valueOf(q.iterate().next().toString());
} finally {
HibernateUtil.closeSession();
}
return resu;
}
@Override
//单字段模糊查询
public List<T> findByFields(String hql, String fields[], String condition) {
Session s = null;
String findhql=hql;
if(fields!=null && condition!=null && fields.length>0 && !condition.equals("") ){
findhql =findhql + " where 1=1 and (";
for(int i=0;i<fields.length-1;++i){
findhql += fields[i]+" like '%" + condition + "%' or ";
}
findhql += fields[fields.length-1]+" like '%" + condition + "%') ";
}
try {
s = HibernateUtil.getThreadLocalSession();
Query query=s.createQuery(findhql);
@SuppressWarnings("unchecked")
List<T> list=query.list();
return list;
} finally {
HibernateUtil.closeSession();
}
}
}
继承 DaoHibernate< User>以实现具体功能(以UserDao为例) :
package com.edu.dao.user;
import org.springframework.stereotype.Repository;
import com.edu.dao.DaoHibernate;
import com.edu.entity.user.User;
@Repository
public class UserDao extends DaoHibernate<User> {
// 通过姓名、密码查询用户
public User findBynameAndPassword(User user) {
String hql = "from User u where u.userName=? and u.userPassword=?";
String param[] = { user.getUserName(), user.getUserPassword() };
User user1 = this.findOne(hql, param);
return user1;
}
// 通过姓名查询用户
public User findByname(User user) {
String hql = "from User u where u.userName=?";
String param[] = { user.getUserName() };
User user1 = this.findOne(hql, param);
return user1;
}
// 修改用户密码: 修改 对象use的密码为newPasswoed
public int updatePassword(User user, String newPassword) {
User user1 = this.findBynameAndPassword(user);
user1.setUserPassword(newPassword);
return this.update(user1);
}
}
自动生成mapping:资源文件与class之间的对应映射关系:
可参考文章:
《Java EE编程技术》综合应用系统开发_作业管理系统_Struts2_Hibernate_设计报告
一、连接数据源:
为方便使用我们先连接数据源(即使用IDE方式直接与数据库进行连接,以便于我们更加直观的使用数据库):
选择MySQL输入相应的用户名、密码、URL
(jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai)等配置信息即可。
二、hibernate的引入与整合:
- 首先导入必须的jar包:
在module中引入hibernate tools工具:
接下来即可自动生成配置hibernate.cfg.xml。
此时选择自动生成实体和对应的配置文件:
对应的实体类和配置文件已经生成完毕。
(根据软件工程思想,这属于逆向工程)(由于数据库我们已经建立完毕,因此这里采用的是逆向的,如果我们一开始确立的对象是java对象,我们也可以利用hibernate生成对应的数据库表文件,则称为正向):
正向工程:Java实体类 ---->mapping---- > DB数据库关系表。
逆向工程:先创建DB数据库关系表,用工具生成生成mapping 和Java实体类。
自动生成后的文件:
(1)映射文件StudentEntity.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="entity_hibernate.StudentEntity" table="student" schema="homework">
<id name="sId">
<column name="s_id" sql-type="int(11)"/>
</id>
<property name="sPassword">
<column name="s_password" sql-type="varchar(20)" length="20" not-null="true"/>
</property>
<property name="sName">
<column name="s_name" sql-type="varchar(20)" length="20" not-null="true"/>
</property>
<property name="sCollege">
<column name="s_college" sql-type="varchar(30)" length="30" not-null="true"/>
</property>
<property name="sDepartment">
<column name="s_department" sql-type="varchar(30)" length="30" not-null="true"/>
</property>
<property name="sClass">
<column name="s_class" sql-type="int(10)" not-null="true"/>
</property>
<property name="sSex">
<column name="s_sex" sql-type="varchar(10)" length="10" not-null="true"/>
</property>
<property name="sEmail">
<column name="s_email" sql-type="varchar(30)" length="30" not-null="true"/>
</property>
</class>
</hibernate-mapping>
(2)StudentEntity:
package entity_hibernate;
import javax.persistence.*;
import java.util.Objects;
@Entity
@Table(name = "student", schema = "homework", catalog = "")
public class StudentEntity {
private int sId;
private String sPassword;
private String sName;
private String sCollege;
private String sDepartment;
private Integer sClass;
private String sSex;
private String sEmail;
@Id
@Column(name = "s_id", nullable = false)
public int getsId() {
return sId;
}
public void setsId(int sId) {
this.sId = sId;
}
@Basic
@Column(name = "s_password", nullable = true, length = 20)
public String getsPassword() {
return sPassword;
}
public void setsPassword(String sPassword) {
this.sPassword = sPassword;
}
@Basic
@Column(name = "s_name", nullable = true, length = 20)
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
@Basic
@Column(name = "s_college", nullable = true, length = 30)
public String getsCollege() {
return sCollege;
}
public void setsCollege(String sCollege) {
this.sCollege = sCollege;
}
@Basic
@Column(name = "s_department", nullable = true, length = 30)
public String getsDepartment() {
return sDepartment;
}
public void setsDepartment(String sDepartment) {
this.sDepartment = sDepartment;
}
@Basic
@Column(name = "s_class", nullable = true)
public Integer getsClass() {
return sClass;
}
public void setsClass(Integer sClass) {
this.sClass = sClass;
}
@Basic
@Column(name = "s_sex", nullable = true, length = 10)
public String getsSex() {
return sSex;
}
public void setsSex(String sSex) {
this.sSex = sSex;
}
@Basic
@Column(name = "s_email", nullable = true, length = 30)
public String getsEmail() {
return sEmail;
}
public void setsEmail(String sEmail) {
this.sEmail = sEmail;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StudentEntity that = (StudentEntity) o;
return sId == that.sId &&
Objects.equals(sPassword, that.sPassword) &&
Objects.equals(sName, that.sName) &&
Objects.equals(sCollege, that.sCollege) &&
Objects.equals(sDepartment, that.sDepartment) &&
Objects.equals(sClass, that.sClass) &&
Objects.equals(sSex, that.sSex) &&
Objects.equals(sEmail, that.sEmail);
}
@Override
public int hashCode() {
return Objects.hash(sId, sPassword, sName, sCollege, sDepartment, sClass, sSex, sEmail);
}
}
(3)当然这里还会在hibernate.cfg.xml中生成资源与类的映射对应关系,这里不再赘述。
11、到这里JDBC,c3p0,hibernate的基本配置就基本结束了,我们可以发现配置文件是逐渐增多的,封装也是逐步完善的。通过对底层工具类模板的逐步封装,我们在dao层编写项目逻辑时(对数据库的基本操作)也逐步趋于简洁。
12、Spring对上述内容的整合:
可参考文章:
《Java EE编程技术》综合应用系统开发_作业管理系统_Spring_Struts2_Hibernate_设计报告
applicationContext.xml(不再需要c3p0.properties文件,属性全部配置在该文件中,同时hibernate.cfg.xml文件也不再需要配置c3p0属性,但是需要一个最初的赋值配置,即db.properties)(在hibernate.cfg.xml文件中也不再需要配置资源与类的映射关系,只需在该文件中配置自动扫描注解方式配置的hibernate类文件等信息即可):
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 配置自动扫描的包: 自动加载构建bean,需要加入 aop 对应的 jar 包 -->
<context:component-scan base-package="com.edu"></context:component-scan>
<!-- 导入资源文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置 C3P0 数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
</bean>
<!-- 配置 SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="mappingLocations" value="classpath:com/edu/entity/*/*.hbm.xml"></property>
<!-- 自动扫描注解方式配置的hibernate类文件 -->
<property name="packagesToScan">
<list>
<value>com.edu.entity.card.*</value>
<value>com.edu.entity.user.*</value>
</list>
</property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- 配置事务通知属性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 定义事务传播属性 -->
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="retrieve*" propagation="REQUIRED" />
<tx:method name="revert*" propagation="REQUIRED" />
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
<tx:method name="*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 配置事务切面 -->
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* com.edu.service..*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
</aop:config>
</beans>
当然在配置applicationContext.xml之前还应在web.xml中配置applicationContext.xml位置等,web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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>
</web-app>
db.properties:
jdbc.user=root
jdbc.password=123456mjg
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/homework?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jdbc.initPoolSize=5
jdbc.maxPoolSize=10
hibernate.cfg.xml(无需c3p0配置和资源映射关系配置):
<?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="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="jdbc.batch_size">20</property>
<property name="connection.autocommit">true</property>
<!-- 显示sql语句 -->
<property name="show_sql">true</property>
<property name="connection.useUnicode">true</property>
<property name="connection.characterEncoding">UTF-8</property>
<property name="hibernate.hbm2ddl.auto">update</property>
</session-factory>
</hibernate-configuration>
config文件夹下内容如下:
上述config文件夹下还有日志配置log4j.xml(与Struts、hibernate等配置无关):
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="com.opensymphony.xwork2" level="debug"/>
<Logger name="org.apache.struts2" level="debug"/>
<Root level="warn">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
13、题外话(Struts配置与使用):
这里采用的是xml配置,也可以采用注解配置。
可参考文章:
《Java EE编程技术》综合应用系统开发_作业管理系统_Struts2_设计报告
config文件夹下struts.xml文件内容:
特别注意:
<!-- Struts的对象工厂是Spring -->
<constant name="struts.objectFactory" value="spring" />
源配置文件:
<?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>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" />
<!-- Struts的对象工厂是Spring -->
<constant name="struts.objectFactory" value="spring" />
<include file="struts/struts-*.xml"></include>
</struts>
struts其他属性配置模板:
<?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>
<!-- 启用动态方法调用 -->
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<!-- 开发提示:出错时打印更详细的信息-->
<constant name="struts.devMode" value="false" />
<!--指定编码集,等价HttpServletRequest.setCharacterEncodint方法-->
<constant name="struts.i18n.encoding" value="UTF-8" />
<!--设置浏览器是否缓存静态内容,开发阶段关闭,运行时开启-->
<constant name="struts.serve.static.browserCache" value="false" />
<!--当struts.xml配置文件修改后,系统是否重新加载该文件-->
<constant name="struts.configuration.xml.reload" value="true" />
<!-- 能够重新加载国际化文件-->
<constant name="struts.i18n.reload = true" value="true" />
<!-- 指定请求的后缀是.do或.action,指定多个请求后缀用逗号分隔-->
<!-- <constant name="struts.action.extension" value="do,action"/>-->
<!-- 添加login的配置信息 -->
<include file="struts-login.xml"/>
</struts>
action name是调用Action方法的名字,class是对应的Action类,method是对应的execute方法。
此处关于struts.xml配置文件记录一个bug:
< constant name=“struts.action.extension” value=“do,action” />
该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。起初要访问的资源不属于action,跳转就出现404,即被struts2拦截掉了。
因此一定要注意配置文件选合适的,配正确的。
config文件夹->struts文件夹下struts-user.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>
<package name="default" namespace="/user" extends="struts-default">
<action name="register" class="com.edu.action.user.UserAction" method="userRegister" >
<result name="success">/user/register_success.jsp</result>
<result name="error">/user/register.jsp</result>
<result name="input">/user/register.jsp</result>
</action>
<action name="login" class="com.edu.action.user.UserAction" method="userLogin">
<result name="input">/user/login.jsp</result>
<result name="failure">/user/login.jsp</result>
<result name="success">/user/login_success.jsp</result>
</action>
</package>
</struts>
对于struts还可以进行拦截器配置(例如对文件的上传下载):
<?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>
<!-- 配置国际化资源文件 -->
<constant name="struts.custom.i18n.resources" value="globalMessages" />
<constant name="struts.i18n.encoding" value="UTF-8" />
<!-- 配置fileupload拦截器 -->
<package name="default" namespace="/" extends="struts-default">
<action name="fileupload" class="com.edu.action.upload.FileUploadAction"
method="execute">
<result name="success">/upLoadSuccess.jsp</result>
<result name="input">/inputFile.jsp</result>
<interceptor-ref name="fileUpload">
<!-- 配置允许文件上传的文件类型 -->
<param name="allowedType">image/jpeg,image/gif</param>
<!-- 配置允许上传的文件大小,以字节为单位,这里设为10M -->
<param name="maximumSize">1048576</param>
</interceptor-ref>
<!-- 引用系统默认的拦截器 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
<action name="fileDownload" class="com.edu.action.download.DownLoadAction">
<result type="stream">
<param name="bufferSize">4096</param>
</result>
</action>
</package>
</struts>
当然struts配置action也可以通过注解进行配置,不必采用struts-user.xml文件进行配置,直接将对应逻辑(返回值等)通过注解方式写到Action类中,比如CardAction:
注意内容:
注解表示命名空间与继承的父包:
@Namespace("/card")
@ParentPackage("struts-default") //表示继承的父包
注意逻辑处理后的返回值及返回方式:
@Action( //表示请求的Action及处理方法
value="insert",
results={@Result(name="success",location="/find",type="redirectAction")}
)
public String insert() throws Exception {
cardService.insert(card);
msg="插入一条记录成功!";
return "success";
}
源代码:
package com.edu.action.card;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.edu.entity.card.Card;
import com.edu.service.card.ICardService;
import com.opensymphony.xwork2.ActionSupport;
@Controller("com.edu.action.card.CardAction")
@Scope("prototype")
@Namespace("/card")
@ParentPackage("struts-default") //表示继承的父包
public class CardAction extends ActionSupport {
private static final long serialVersionUID = 1L;
@Resource
private ICardService cardService;
private Card card; //传入提交值(插入记录)
//提交页面——查询信息提交
private String condition;//查询条件
private String[] checkList; //可以选择多条记录的复选框所形成的记录序号的字符串
private int id; //单记录时的主键号
private String order; //设置查询结果排序方式:按记录号升序或降序(添加的先后次序)
private long pageNo; //设置查询结果要显示的分页页码号
private int pageSize; //设置查询结果要显示的分页,每页要显示的记录条数(当不设置时,不分页)
//返回执行结果的返回信息
private long recordCount;//查询满足条件的记录总条数
private long pageCount;//查询出记录的总页数(按所设置的每页条数后,形成的页总数)
private List<Card> listCard;//传出查询结果集合
private String msg; //返回运行后的信息
private HttpSession session;
public CardAction() {
}
@Action( //表示请求的Action及处理方法
value="insert",
results={@Result(name="success",location="/find",type="redirectAction")}
)
public String insert() throws Exception {
cardService.insert(card);
msg="插入一条记录成功!";
return "success";
}
public ICardService getCardService() {
return cardService;
}
public void setCardService(ICardService cardService) {
this.cardService = cardService;
}
@Action( //表示请求的Action及处理方法
value="insertList",
results={@Result(name="success",location="/find",type="redirectAction")}
)
public String insertList() throws Exception {
int n=cardService.insertList(listCard);
msg="插入一组("+n+"条)记录成功!";
return "success";
}
@Action( //表示请求的Action及处理方法
value="delete",
results={@Result(name="success",location="/find",type="redirectAction")}
)
public String delecte() throws Exception {
cardService.delete(id);
msg="删除入一条记录成功!";
return "success";
}
@Action( //表示请求的Action及处理方法
value="delecteList",
results={@Result(name="success",location="/find",type="redirectAction")}
)
public String delecteList() throws Exception {
int ids[]=new int[checkList.length];
for(int i=0;i<checkList.length;++i){
ids[i]=Integer.parseInt(checkList[i]);
}
int n=cardService.deleteList(ids);
msg="删除一组("+n+"条)记录成功!";
return "success";
}
@Action( //表示请求的Action及处理方法
value="find",
results={@Result(name="success",location="/card/list.jsp",type="dispatcher")}
)
public String find() throws Exception {
listCard=cardService.findByCondition(condition, "0");
session=ServletActionContext.getRequest().getSession();
session.setAttribute("condition", condition);
session.setAttribute("order", order);
return "success";
}
@Action( //表示请求的Action及处理方法
value="findupdate",
results={@Result(name="success",location="/card/update.jsp",type="dispatcher")}
)
public String findUpdate() throws Exception {
card=cardService.findById(id, "0");
return "success";
}
@Action( //表示请求的Action及处理方法
value="retrieve",
results={@Result(name="success",location="/find",type="redirectAction")}
)
public String retrieve() throws Exception {
int ids[]=new int[checkList.length];
for(int i=0;i<checkList.length;++i){
ids[i]=Integer.parseInt(checkList[i]);
}
cardService.retrieve(ids);
return "success";
}
@Action( //表示请求的Action及处理方法
value="update",
results={@Result(name="success",location="/find",type="redirectAction")}
)
public String update() throws Exception {
cardService.update(card);
return "success";
}
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
public String getCondition() {
return condition;
}
public void setCondition(String condition) {
this.condition = condition;
}
public String[] getCheckList() {
return checkList;
}
public void setCheckList(String checkList[]) {
this.checkList = checkList;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getOrder() {
return order;
}
public void setOrder(String order) {
this.order = order;
}
public long getPageNo() {
return pageNo;
}
public void setPageNo(long pageNo) {
this.pageNo = pageNo;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public long getRecordCount() {
return recordCount;
}
public void setRecordCount(long recordCount) {
this.recordCount = recordCount;
}
public long getPageCount() {
return pageCount;
}
public void setPageCount(long pageCount) {
this.pageCount = pageCount;
}
public List<Card> getListCard() {
return listCard;
}
public void setListCard(List<Card> listCard) {
this.listCard = listCard;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public HttpSession getSession() {
return session;
}
public void setSession(HttpSession session) {
this.session = session;
}
}
注意Action中type类型的取值:
尤其注意type="dispatcher"与type=“redirect”、type="redirectAction"的区别:
type="dispatcher"为默认类型,表示转发,上一个界面中的信息不会丢失,可以被获取,而type=“redirect”、type="redirectAction"表示重定向到URL或者Action,上一个界面的信息将会丢失。
易产生问题:在EL表达式需要获取值时应采用type=“dispatcher”,而不是type=“redirect”。
type的一些其他取值:
stream:向浏览器发送 InputStream 对象,通常用于处理文件下载(比如在导出Excel数据时),还可用于 Ajax 数据。
当然还有chain,用于处理Action链,被跳转的Action中仍能获取上个页面的值如request信息等等。
对于type的stream取值:向浏览器发送 InputStream 对象,用于处理文件下载(导出Excel数据时举例):
可参考文章:
文件上传下载与Excel、数据表数据之间的转换
struts还可以配置拦截器,放在Action类的同一个包下,如(一定要注意名字格式):
其中UserAction-register-validation.xml配置文件内容如下:
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.2//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
<validators>
<!-- 设置输入验证:验证(账号)学号、密码、邮件格式以及密码是否一致等 -->
<field name="studentEntity.SId">
<field-validator type="int" short-circuit="true">
<message>用户账号不能为空!且用户账号格式应为数字型账号!</message>
</field-validator>
</field>
<field name="studentEntity.SName">
<field-validator type="requiredstring" short-circuit="true">
<param name="trim">true</param>
<message>用户名不能为空!</message>
</field-validator>
<field-validator type="regex">
<param name="regexExpression"><![CDATA[^[a-zA-Z]\w*$]]></param>
<message>用户名格式不正确!</message>
</field-validator>
</field>
<field name="studentEntity.SPassword">
<field-validator type="requiredstring" short-circuit="true">
<param name="trim">true</param>
<message>密码不能为空!</message>
</field-validator>
<field-validator type="stringlength">
<param name="minLength">6</param>
<message>密码长度不能小于6!</message>
</field-validator>
</field>
<field name="re_password">
<field-validator type="requiredstring" short-circuit="true">
<message>确认密码不能为空!</message>
</field-validator>
<field-validator type="fieldexpression">
<param name="expression"><![CDATA[re_password==studentEntity.sPassword]]></param>
<message>密码不一致!</message>
</field-validator>
</field>
<field name="studentEntity.SEmail">
<field-validator type="email" >
<message>你的电子邮件地址必须是一个有效的电邮地址!</message>
</field-validator>
</field>
</validators>
UserAction(此处userService采用注解配置并通过Spring注入方式直接注入,同时注意struts-action与jsp/html界面的属性名(name)之间的一一对应关系同时注明get、set函数否则将会出现404的错误):
@Resource
private IUserService userService ;
package com.edu.action.user;
import javax.annotation.Resource;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.edu.entity.user.User;
import com.edu.service.user.IUserService;
import com.opensymphony.xwork2.ActionSupport;
@Controller
@Scope("prototype")
public class UserAction extends ActionSupport {
private static final long serialVersionUID = 1L;
//对于user和re_password、msg属性需要使用get、set函数
private User user;
//用于注册时验证密码是否一致
private String re_password;
private String msg;
//不再new,而是采用spring注入方式
@Resource
private IUserService userService ;
// 用户登录Action方法
public String userLogin() throws Exception {
String forward = null;
User user2 = userService.findBynameAndPassword(user);
if (user2 != null) {
forward = "success"; //登录成功标记值
user.setUserRealName(user2.getUserRealName());
} else {
msg="用户不存在 或密码不正确,登录失败,请重新登录或注册!";
forward = "failure";//登录失败标记值
}
return forward;
}
// 用户注册Action方法
public String userRegister() throws Exception {
String forward =null;
int flag = 0;
User user2 = userService.findByname(user);
if (user2!=null && (user2.getUserName().trim()).equals((user.getUserName()).trim())) {
msg="用户:"+ user.getUserName()+" 已经存在,请重新注册!";
forward = "error"; //用户名已被占用标记标记值
} else {
flag = userService.insert(user);
if (flag == 1) {
forward = "success"; //成功注册标记值
}else{
msg="数据库写错误!!";
forward ="error";
}
}
return forward;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getRe_password() {
return re_password;
}
public void setRe_password(String re_password) {
this.re_password = re_password;
}
}
jsp/html界面(以注册界面register.jsp为例,注意属性名(name)与action之间的一一对应关系):
<%@ page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>注册页面</title>
</head>
<body>
<s:fielderror cssStyle="color: red"></s:fielderror>
<font color="red"><s:property value="msg" /></font><br>
<h3 align="left">欢迎注册我们的系统,请认真填写您的信息</h3>
<form name="register" action="<%=basePath%>user/register" method="post">
<table>
<tr>
<td align="right">账户名:</td>
<td><input type="text" name="user.userName" value="${user.userName}" ></td>
</tr>
<tr>
<td align="right">为您的账户设置密码:</td>
<td><input type="password" name="user.userPassword"></td>
</tr>
<tr>
<td align="right">再次确认您的密码:</td>
<td><input type="password" name="re_password" ></td>
<td></td>
</tr>
<tr>
<td align="right">真实姓名:</td>
<td><input type="text" name="user.userRealName" value="${user.userRealName}"></td>
<td></td>
</tr>
<tr>
<td align="right"><input type="submit" value="提交"></td>
<td colspan="2"><input type="reset" value="重新填写"></td>
</tr>
</table>
</form>
</body>
</html>
上述Action类包含实体类,这里叙述一下编写模型类(实体类)entity的规范:
注意必须遵守JavaBean规范,必须要有默认构造函数,注意命名规范。
这里记录一个bug:在测试Struts2的Action接收jsp页面时表单数据为null,实际上就是由于命名不规范导致的原因:Struts对变量的get和set方法有严格的要求,以get为例,如果你的变量分别是username,userName,uName,那么对应的get方法就是getUsername(),getUserName(),getUName(),总结起来就是首字母必须大写。Eclipse/IDEA生成get方法一般是符合这一规范的,但是当变量名为uName时,默认生成的时getuName(),而不是正确的 getUName(),这时候就不符合struts2的命名规范了,然后非常难发现这个问题,因为越是eclipse/idea等IDE自动生成的代码,我们越相信,但实质上已经错了,struts2内部赋值的时候便会找不到该值即null。(参考:https://blog.csdn.net/Yuwen_forJava/article/details/80178222)
当时在测试StudentAction与jsp传值时便一直在报null错误,代码静态结构分析也没有观察出有什么错误,而且在在动态分析下发现初始传值部分即为null而不是数据库或者dao层之间的问题,完全可以确定是发生在StudentAction与jsp页面之间的传值错误。修改student实体类的命名规范后发现传值成功。(细节决定成败,一定注意规范。)(不过这也是struts一点非常不好的地方,格式过于死板。在文件上传下载时命名规范更是有着严格的要求。)
至此,struts配置以及spring+struts+hibernate配置基本完毕。
14、SpringBoot+Mybatis配置:
采用Maven方式pom.xml对相关依赖文件进行导入:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hqyj</groupId>
<artifactId>shixun</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>shixun</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis相关依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--添加阿里JSon-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
<!--阿里数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<!-- 添加japidocs依赖 -->
<dependency>
<groupId>io.github.yedaxia</groupId>
<artifactId>japidocs</artifactId>
<version>1.4.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml配置(尤其需要注意格式,例如空格等,也可采用application.properties配置):
例一:
spring:
#数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/chongwu?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
username: root
password: 123456mjg
#配置资源目录:
resources:
static-locations: classpath:/static/
web:
resources:
static-locations: classpath:/META-INF/resources,classpath:/resources,classpath:/static,classpath:/public,file:${files}
#所有的请求都视为静态路径
mvc:
static-path-pattern: /**
files: E:/images/imgs
server:
port: 8082
mybatis:
mapper-locations: classpath*:mapper/*.xm
例二:
server:
port: 8088
#spring:
# datasource:
# url: jdbc:mysql://localhost:3306/nongda?useUnicode=true&characterEncoding=utf8&useSSL=true
# data-username: root
# data-password: root
# driver-class-name: com.mysql.cj.jdbc.Driver
# type: com.alibaba.druid.pool.DruidDataSource
spring:
http:
encoding:
charset: UTF-8
force: true
enabled: true
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
platform: mysql
url: jdbc:mysql://127.0.0.1:3306/nongda?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
username: root
password: 123456mjg
#初始化链接数
initialSize: 5
#最小的空闲连接数
minIdle: 5
#最大活动连接数
maxActive: 20
#从池中取连接的最大等待时间,单位ms
maxWait: 60000
#每XXms运行一次空闲连接回收器
timeBetweenEvictionRunsMillis: 60000
#池中的连接空闲XX毫秒后被回收
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT1FROMDUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
filters: stat,wall,log4j
logSlowSql: true
#表示所有的访问都经过静态资源路径
mvc:
static-path-pattern: /**
web:
resources:
static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${files}
files: E:/pics/img/
mybatis:
mapper-locations: classpath*:mapper/*.xml
配置mybatis Mapper文件(放置在资源resources文件夹下):
controller层接收前端请求进行处理:
package com.hqyj.shixun.controller;
import com.alibaba.fastjson.JSONObject;
import com.hqyj.shixun.entity.BackUser;
import com.hqyj.shixun.service.BackUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/back")
public class BackUserController {
@Autowired
private BackUserService backUserService;
@RequestMapping("/getBackUsers")
public Object getBackUsers(String userName,String password){
JSONObject jsonObject=new JSONObject();
List<BackUser> backUsers=backUserService.getBackUsers(userName,password);
jsonObject.put("code",0);
jsonObject.put("data",backUsers);
return jsonObject;
}
@RequestMapping("/saveBackUser")
public Object saveBackUser( String userName,String password,String nickName){
JSONObject jsonObject =new JSONObject();
int backUserNameCount=backUserService.getBackUserNameCount(userName);
if(backUserNameCount>0){
jsonObject.put("code",2);
jsonObject.put("data","用户名已存在");
return jsonObject;
}
BackUser backUser=new BackUser();
backUser.setUserName(userName);
backUser.setPassword(password);
backUser.setNickName(nickName);
int num=backUserService.saveBackUser(backUser);
if(num>0){
jsonObject.put("code",0);
jsonObject.put("data","操作成功");
}else{
jsonObject.put("code",1);
jsonObject.put("data","操作失败");
}
return jsonObject;
}
@RequestMapping("/updateBackUser")
public Object updateBackUser(int id, String userName,String password,String nickName){
JSONObject jsonObject=new JSONObject();
BackUser backUser=new BackUser();
backUser.setId(id);
backUser.setUserName(userName);
backUser.setPassword(password);
backUser.setNickName(nickName);
int num=backUserService.updateBackUser(backUser);
if(num>0){
jsonObject.put("code",0);
jsonObject.put("data","修改成功");
}else{
jsonObject.put("code",1);
jsonObject.put("data","修改失败");
}
return jsonObject;
}
@RequestMapping("/deleteBackUser")
public Object deleteBackUser(int id){
JSONObject jsonObject = new JSONObject();
int num=backUserService.deleteBackUser(id);
if(num>0){
jsonObject.put("code",0);
jsonObject.put("data","删除成功");
}else{
jsonObject.put("code",1);
jsonObject.put("data","删除失败");
}
return jsonObject;
}
}
service接收controller层传来的请求进行业务处理(接口与实现imp):
接口:
package com.hqyj.shixun.service;
import com.hqyj.shixun.entity.BackUser;
import java.util.List;
public interface BackUserService {
List<BackUser> getBackUsers(String userName, String password);
int saveBackUser(BackUser backUser);
int getBackUserNameCount(String userName);
int updateBackUser(BackUser backUser);
int deleteBackUser(int id);
}
实现:
package com.hqyj.shixun.service.imp;
import com.hqyj.shixun.dao.BackUserDao;
import com.hqyj.shixun.entity.BackUser;
import com.hqyj.shixun.service.BackUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BackUserServiceImp implements BackUserService {
@Autowired
private BackUserDao backUserDao;
@Override
public List<BackUser> getBackUsers(String userName, String password) {
return backUserDao.getBackUsers(userName,password);
}
@Override
public int saveBackUser(BackUser backUser) {
return backUserDao.saveBackUser(backUser);
}
@Override
public int getBackUserNameCount(String userName) {
return backUserDao.getBackUserNameCount(userName);
}
@Override
public int updateBackUser(BackUser backUser) {
return backUserDao.updateBackUser(backUser);
}
@Override
public int deleteBackUser(int id) {
return backUserDao.deleteBackUser(id);
}
}
编写Dao层接口以期实现数据库访问:
package com.hqyj.shixun.dao;
import com.hqyj.shixun.entity.BackUser;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface BackUserDao {
List<BackUser> getBackUsers(String userName,String password);
int saveBackUser(BackUser backUser);
int getBackUserNameCount(String userName);
int updateBackUser(BackUser backUser);
int deleteBackUser(int id);
}
编写Mapper映射关系实现真正的数据库操作:
例一:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hqyj.shixun.dao.BackUserDao">
<resultMap id="BackUserResultMap" type="com.hqyj.shixun.entity.BackUser" >
<id column="id" property="id"/>
<result column="user_name" property="userName"/>
<result column="password" property="password"/>
<result column="nick_name" property="nickName"/>
</resultMap>
<select id="getBackUsers" resultMap="BackUserResultMap">
select * from back_user
<where>
<if test="userName!=null and userName!=''">
and user_name=#{userName}
</if>
<if test="password!=null and password!=''">
and password=#{password}
</if>
</where>
</select>
<insert id="saveBackUser" parameterType="com.hqyj.shixun.entity.BackUser">
insert into back_user (user_name,password,nick_name) values (#{userName},#{password},#{nickName})
</insert>
<select id="getBackUserNameCount" resultType="java.lang.Integer">
select count(*) from back_user where user_name=#{userName}
</select>
<update id="updateBackUser" parameterType="com.hqyj.shixun.entity.BackUser">
update back_user
<set>
<if test="userName != null">
user_name=#{userName}
</if>
<if test="password!=null">
password=#{password}
</if>
<if test="nickName!=null">
nick_name=#{nickName}
</if>
</set>
where id=#{id}
</update>
<delete id="deleteBackUser" parameterType="java.lang.Integer">
delete from back_user where id=#{id}
</delete>
</mapper>
例二:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hqyj.shixun.dao.AnimalDao">
<resultMap id="AnimalResultMap" type="com.hqyj.shixun.entity.Animal" >
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="main_img" property="mainImg"/>
<result column="price" property="price"/>
</resultMap>
<select id="getAnimals" resultMap="AnimalResultMap">
select * from animal where 1=1
<if test="type_id!=null and type_id!=0">
and type_id=#{type_id}
</if>
</select>
<select id="findAnimalCount" resultType="java.lang.Integer">
select count(*) from animal where 1=1
<if test="backId!=null and backId!=0">
and back_id=#{backId}
</if>
<if test="typeId!=null and typeId!=0">
and type_id=#{typeId}
</if>
</select>
</mapper>
实体类补充:
package com.hqyj.shixun.entity;
public class BackUser {
private int id;
private String userName;
private String password;
private String nickName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
}
注意内容:注意上面的Mapper文件中数据表与实体类之间的映射关系以及Mapper文件与Dao层之间的映射关系(特别注意方法名、传参类型、返回结果、获取变量方式等),还需注意where 1=1条件永真的用处,可参考:where 1=1有什么用?、SQL where 1=1的作用,注意#{}与 $ {}的区别,可参考文章:#{}与 $ {}的区别、#{}与 $ {}的区别
15、题外话(文档的自动生成、Japidocs的使用)
添加Japidocs依赖:
<!-- 添加japidocs依赖 -->
<dependency>
<groupId>io.github.yedaxia</groupId>
<artifactId>japidocs</artifactId>
<version>1.4.3</version>
</dependency>
可在主运行界面设置每次运行自动生成:
package com.hqyj.shixun;
import com.hqyj.shixun.controller.JApiDocsInitialization;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@MapperScan("com.hqyj.shixun.dao")
public class ShixunApplication {
public static void main(String[] args) {
SpringApplication.run(ShixunApplication.class, args);
}
// // 启动时重新生成api文档
// JApiDocsInitialization.initialize();
}
将JApiDocsInitialization类放在controller包下,也可直接手动运行(注意配置):
package com.hqyj.shixun.controller;
import io.github.yedaxia.apidocs.Docs;
import io.github.yedaxia.apidocs.DocsConfig;
/**
* japi文档生成初始化配置
*
*/
public class JApiDocsInitialization {
/**
* JApi run test
*
* @param args
*/
public static void main(String[] args) {
initialize();
}
/**
* 自动生成api文档
*/
public static void initialize() {
DocsConfig config = new DocsConfig();
String projectPath = System.getProperty("user.dir");
config.setProjectPath(projectPath); // 项目根目录
config.setProjectName("shixun"); // 项目名称
config.setApiVersion(""); // 声明该API的版本
// 为了防止服务器上无法发现静态资源生成位置,需要指定项目的绝对路径
config.setDocsPath(projectPath + "/src/main/resources/static/apidoc"); // 生成API 文档所在目录
config.setAutoGenerate(Boolean.TRUE); // 配置自动生成
Docs.buildHtmlDocs(config); // 执行生成文档
}
}
config.setDocsPath(projectPath + “/src/main/resources/static/apidoc”); // 生成API 文档所在目录
可在相关目录下找到生成结果(这里格式为html):