MyEclipse的反向生成工具-->hibernate反轉引擎引擎(MyEclipse自帶的插件)
來反轉生成實體類和對應的映射文件持久層的設計(基於泛型+反射)圖解,以下圖所示:javascript
package com.itheima.bos.dao.base;
import java.io.Serializable;
import java.util.List;
/*
* 抽取持久層通用方法:增刪改查+分頁+...
*/
public interface IBaseDao<T> {
// 增刪改查
public void save(T entity);
public void delete(T entity);
public void update(T entity);
// 由於id不論是int類型仍是string類型,他們都實現了Serializable序列化接口,使用Serializable類型,或者更狠一點:就用Object類型
public T findById(Serializable id);
public List<T> findAll();
// 分頁
// ...
}
通用接口實現代碼:
BaseDaoImpl.javacss
package com.itheima.bos.dao.base.impl;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import javax.annotation.Resource;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.itheima.bos.dao.base.IBaseDao;
/*
* 持久層通用實現
*/
public class BaseDaoImpl<T> extends HibernateDaoSupport implements IBaseDao<T> {
// 聲明實體類型
private Class<T> entityClass; // Class也是一個class,Class表明的是類型
// 在構造方法中動態獲取操做要用的實體類型
public BaseDaoImpl() { // this是當前實例化對象,經過getClass(),獲得當前類的類型,getGenericSuperclass() 得到帶有泛型的父類,getSuperclass() 得到該類的父類
// Type是 Java 編程語言中全部類型的公共高級接口。它們包括原始類型、參數化類型、數組類型、類型變量和基本類型。
Type type = this.getClass().getGenericSuperclass();
// ParameterizedType 參數化類型,即泛型
ParameterizedType pt = (ParameterizedType)type;
// getActualTypeArguments() 獲取參數化類型的數組,泛型可能有多個
Type[] actualTypeArguments = pt.getActualTypeArguments();
entityClass = (Class<T>) actualTypeArguments[0];
}
// 使用註解方式進行依賴注入setter方法
// @Autowired 註解,它能夠對類成員變量、方法及構造函數進行標註,完成自動裝配的工做。注意:@Autowired 默認按類型匹配(byType)進行注入的。
// 若是須要按名稱(byName)匹配的話,可使用@Qualifier註解與@Autowired結合,請注意必須在xml配置中啓動註解驅動。
// @Resource 假若既不指定name也不指定type屬性,Spring容器將經過反射技術默認按byName模式進行注入的。
// 該註解需導入import javax.annotation.Resource;
// 此時Spring只會嘗試將屬性名與bean名稱進行匹配,若是找到則注入依賴bean。
// 因爲public final void setSessionFactory(SessionFactory sessionFactory) {...}是final的,因此須要咱們自定義方法,再去使用super去調用它。
@Resource
public void setMySessionFactory(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
public void save(T entity) {
this.getHibernateTemplate().save(entity);
}
public void delete(T entity) {
this.getHibernateTemplate().delete(entity);
}
public void update(T entity) {
this.getHibernateTemplate().update(entity);
}
public T findById(Serializable id) {
this.getHibernateTemplate().get(entityClass, id);
return null;
}
public List<T> findAll() {
String hql = "from " + entityClass.getSimpleName(); // 注意from後面有空格
return this.getHibernateTemplate().find(hql);
}
}
咱們再補上IUserDao和UserDaoImpl的示例代碼:
IUserDao.javahtml
package com.itheima.bos.dao;
import com.itheima.bos.dao.base.IBaseDao;
import com.itheima.bos.domain.User;
public interface IUserDao extends IBaseDao<User> {
}
UserDaoImpl.javajava
package com.itheima.bos.dao.impl;
// import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import com.itheima.bos.dao.IUserDao;
import com.itheima.bos.dao.base.impl.BaseDaoImpl;
import com.itheima.bos.domain.User;
@Repository // IUserDaoImpl對象默認是單例的,單例對象建立的時機:在applicationContext.xml配置文件加載,執行組件掃描,建立工廠的時候,單例對象被建立了
// @Scope("prototype") 多例,多例對象建立的時機:在getBean() 真正從工廠獲取的對象時候才建立
public class UserDaoImpl extends BaseDaoImpl<User> implements IUserDao {
}
表現層的設計圖解,以下圖所示:jquery
package com.itheima.bos.web.action.base;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class BaseAction<T> extends ActionSupport implements ModelDriven<T> {
// 聲明模型對象
private T model;
public T getModel() {
return model;
}
// 在構造方法中動態獲取操做要用的實體類型,而後經過反射建立模型對象
public BaseAction() {
// Type是 Java 編程語言中全部類型的公共高級接口。它們包括原始類型、參數化類型、數組類型、類型變量和基本類型。
Type type = this.getClass().getGenericSuperclass();
// ParameterizedType 參數化類型,即泛型
ParameterizedType pt = (ParameterizedType)type;
// getActualTypeArguments() 獲取參數化類型的數組,泛型可能有多個
Type[] actualTypeArguments = pt.getActualTypeArguments();
// 獲取操做要用的實體類型
Class<T> entityClass = (Class<T>) actualTypeArguments[0];
try {
// 經過反射建立模型對象
model = entityClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
咱們再補UserAction的示例代碼:
UserAction.javaweb
package com.itheima.bos.web.action;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.itheima.bos.domain.User;
import com.itheima.bos.web.action.base.BaseAction;
@Controller
@Scope("prototype") // 配置對象多例
public class UserAction extends BaseAction<User> {
// 簡單測試struts是否配置成功,測試完刪掉
public String test() {
return "test";
}
}
相應的struts.xml文件須要對userAction進行配置:
struts.xmlajax
<?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.devMode" value="true"/>
<!-- 使Spring對象工廠成爲自動默認值,struts2與spring整合,該句不是必須的,在整合jar中已經配置過了 ,這裏只是爲了強調-->
<constant name="struts.objectFactory" value="spring"/>
<package name="basicstruts2" extends="struts-default">
<!-- 須要進行權限控制的頁面訪問,使用默認的類和默認的方法,默認的類和默認的方法能夠不用寫,這裏寫出來爲了強調 -->
<action name="page_*_*" class="com.opensymphony.xwork2.ActionSupport" method="execute">
<result name="success" type="dispatcher">/WEB-INF/pages/{1}/{2}.jsp</result>
</action>
<!-- 配置userAction-->
<action name="userAction_*" class="userAction" method="{1}">
<result>xxx</result>
</action>
</package>
</struts>
第一步:修改login.jsp頁面,點擊登陸按鈕,提交表單
login.jspspring
......
<form id="loginform" name="loginform" method="post" class="niceform"
action="${pageContext.request.contextPath}/userAction_login.action">
......
<%-- <a href="${pageContext.request.contextPath}/page_common_index.action" id="loginform:j_id19" name="loginform:j_id19"> --%>
<a onclick="document.forms[0].submit()" id="loginform:j_id19" name="loginform:j_id19">
<span id="loginform:loginBtn" class="btn btn-login" style="margin-top:-36px;">登陸</span>
</a>
......
瀏覽器頁面以下圖所示:sql
package com.itheima.bos.web.action;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.ServletActionContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.itheima.bos.domain.User;
import com.itheima.bos.service.IUserService;
import com.itheima.bos.web.action.base.BaseAction;
@Controller
@Scope("prototype") // 配置對象多例
public class UserAction extends BaseAction<User> {
// 注入service
@Resource
private IUserService userServie;
// 經過屬性驅動接收傳遞過來的驗證碼
private String checkcode;
public void setCheckcode(String checkcode) {
this.checkcode = checkcode;
}
public String login() {
// 判斷用戶輸入的驗證碼是否正確
// 先獲取咱們本身生成的驗證碼
String key = (String) ServletActionContext.getRequest().getSession().getAttribute("key");
// 判斷用戶是否有輸入驗證碼和輸入的驗證碼是否和我生成的驗證碼是否相等
if (StringUtils.isNotBlank(checkcode) && checkcode.equals(key)) {
// 說明驗證碼存在且正確
User user = userServie.login(model);
if (user != null) {
// 說明登陸成功,將User放入session域中,並跳轉到系統首頁
ServletActionContext.getRequest().getSession().setAttribute("loginUser", user);
return "home";
} else {
// 說明登陸失敗,設置錯誤提示信息,並跳轉至登陸頁面
// this.addActionError("用戶名或者密碼錯誤"); // 在Struts2中,全部的消息提示都是基於國際化的。
this.addActionError(this.getText("loginError"));
return "login";
}
} else {
// 說明驗證碼錯誤,設置錯誤提示信息,並跳轉至登陸頁面
// this.addActionError("驗證碼錯誤"); // 在Struts2中,全部的消息提示都是基於國際化的。
this.addActionError(this.getText("validatecodeError"));
return "login";
}
}
}
第三步:提供IUserService接口和UserServiceImpl類
IUserService.java數據庫
package com.itheima.bos.service;
import com.itheima.bos.domain.User;
public interface IUserService {
public User login(User model);
}
UserServiceImpl.java
package com.itheima.bos.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.itheima.bos.dao.IUserDao;
import com.itheima.bos.domain.User;
import com.itheima.bos.service.IUserService;
import com.itheima.bos.utils.MD5Utils;
@Service
@Transactional
public class UserServiceImpl implements IUserService {
// 注入dao
@Autowired
private IUserDao userDao;
public User login(User model) {
String username = model.getUsername();
String password = model.getPassword(); // 明文密碼
password = MD5Utils.md5(password); // MD5加密後的密碼
User user = userDao.findByUserNameAndPassWord(username, password);
return user;
}
}
第四步:在IUserDao接口中擴展方法和UserDaoImpl實現類,根據用戶名和密碼查詢用戶
IUserDao.java
package com.itheima.bos.dao;
import com.itheima.bos.dao.base.IBaseDao;
import com.itheima.bos.domain.User;
public interface IUserDao extends IBaseDao<User> {
public User findByUserNameAndPassword(String username, String password);
}
UserDaoImpl.java
package com.itheima.bos.dao.impl;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.itheima.bos.dao.IUserDao;
import com.itheima.bos.dao.base.impl.BaseDaoImpl;
import com.itheima.bos.domain.User;
@Repository // IUserDaoImpl對象默認是單例的,單例對象建立的時機:在applicationContext.xml配置文件加載,執行組件掃描,建立工廠的時候,單例對象被建立了
// @Scope("prototype") 多例,多例對象建立的時機:在getBean() 真正從工廠獲取的對象時候才建立
public class UserDaoImpl extends BaseDaoImpl<User> implements IUserDao {
/*
* 根據用戶名和密碼查詢用戶
*/
public User findByUserNameAndPassword(String username, String password) {
String hql = "from User u where u.username=? and u.password=?";
List<User> list = this.getHibernateTemplate().find(hql, username, password);
if (list != null && list.size() > 0 ) {
return list.get(0);
}
return null;
}
}
第五步:編寫國際化配置文件,在struts.xml中註冊(配置)國際化文件
/bos19/config/message.properties
loginError=\u7528\u6237\u540D\u6216\u8005\u5BC6\u7801\u9519\u8BEF
validatecodeError=\u9A8C\u8BC1\u7801\u9519\u8BEF
struts.xml
......
<!-- 在struts中註冊(配置)國際化文件 -->
<constant name="struts.custom.i18n.resources" value="message"></constant>
......
第六步:在login.jsp頁面中使用struts2提供的標籤展現錯誤提示信息
login.jsp
......
<%@ taglib uri="/struts-tags" prefix="s"%>
......
<font color="red">
    <s:actionerror/>
</font>
示例代碼以下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>messager---消息框控件</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/js/easyui/themes/default/easyui.css">
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/js/easyui/themes/icon.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.8.3.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/easyui/jquery.easyui.min.js"></script>
<!-- 引入中文語言包 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/easyui/locale/easyui-lang-zh_CN.js"></script>
<script type="text/javascript">
$(function() {
// alert();
// window.alert();
// 消息提示框
$.messager.alert("標題", "內容信息", "question");
window.setTimeout(function() {
// 消息提示框(在屏幕的右下角顯示一個消息窗口)
$.messager.show({
title:'歡迎信息',
msg:'歡迎張三登陸系統',
timeout:3000,
showType:'slide'
});
}, 3000);
// 消息確認框
$.messager.confirm("標題", "你肯定刪除當前數據嗎?", function(r) {
alert(r);
});
// 帶有輸入功能的消息確認框
$.messager.prompt("標題", "你肯定刪除當前數據嗎?", function(r) {
alert(r);
});
// 顯示進度提示框
$.messager.progress();
// 延時3秒後關閉進度提示框
window.setTimeout(function() {
$.messager.progress('close');
}, 3000);
});
</script>
</head>
<body>
</body>
</html>
示例代碼以下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>menubutton---菜單按鈕</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/js/easyui/themes/default/easyui.css">
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/js/easyui/themes/icon.css">
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.8.3.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/easyui/jquery.easyui.min.js"></script>
<!-- 引入中文語言包 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/easyui/locale/easyui-lang-zh_CN.js"></script>
</head>
<body>
<a data-options="iconCls:'icon-help',menu:'#mm'" class="easyui-menubutton">控制面板</a>
<!-- 使用div製做下拉菜單選項 -->
<div id="mm">
<!-- 使用子div製做具體的一個選項 -->
<div onclick="alert(111)" data-options="iconCls:'icon-edit'">修改密碼</div>
<div>聯繫管理員</div>
<div class="menu-sep"></div>
<div>退出系統</div>
</div>
</body>
</html>
效果以下圖所示:
第一步:自定義一個攔截器類
BOSLoginInterceptor.java
package com.itheima.bos.web.intereptor;
import org.apache.struts2.ServletActionContext;
import com.itheima.bos.domain.User;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
/*
* 自定義一個struts2攔截器,實現用戶未登陸時,自動跳轉到登陸頁面
*/
public class BOSLoginInterceptor extends MethodFilterInterceptor{
// 攔截方法
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
// 測試自定義攔截器是否工做
// ActionProxy proxy = invocation.getProxy();
// String namespace = proxy.getNamespace();
// String actionName = proxy.getActionName();
// String url = namespace + actionName;
// System.out.println("自定義的struts攔截器執行了" + url);
User user = (User) ServletActionContext.getRequest().getSession().getAttribute("loginUser");
if (user == null) {
// 說明用戶未登陸,跳轉到登陸頁面
return "login";
}
// 不然說明用戶登陸,就放行
return invocation.invoke();
}
}
第二步:在struts.xml中註冊(配置/聲明)自定義的攔截器
......
<!-- 註冊(配置/聲明)攔截器 -->
<interceptors>
<!-- 註冊(配置/聲明)自定義的攔截器 -->
<interceptor name="BOSLoginInterceptor" class="com.itheima.bos.web.intereptor.BOSLoginInterceptor"></interceptor>
<!-- 個人全局攔截器棧中包括: -->
<interceptor-stack name="myStack">
<!-- 一、默認的攔截器棧 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 二、我自定義的攔截器 -->
<interceptor-ref name="BOSLoginInterceptor">
<!-- 自定義的攔截器要配置:須要攔截哪些方法,和須要放過哪些方法 -->
<param name="excludeMethods">login</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 從新定義默認的攔截器棧 -->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
<!-- 配置/聲明全局邏輯結果視圖 -->
<global-results>
<result name="login">/login.jsp</result>
</global-results>
......
/WEB-INF/pages/common/index.jsp
......
<!-- 注意:該表單不是用來提交用的,而是用來制定輸入校驗規則用的 -->
<form id="editPasswordForm">
<table cellpadding=3>
<tr>
<td>新密碼:</td>
<td><input id="txtNewPass" type="Password" class="txt01 easyui-validatebox"
data-options="required:true, validType:'length[4,8]'"
/></td>
</tr>
<tr>
<td>確認密碼:</td>
<td><input id="txtRePass" type="Password" class="txt01 easyui-validatebox"
data-options="required:true, validType:'length[4,8]'"
/></td>
</tr>
</table>
</form>
......
第二步:爲修改密碼的「肯定」按鈕綁定事件
// 爲修改密碼的「肯定」按鈕綁定事件
$("#btnEp").click(function() {
// 進行表單驗證
// 基於jQuery的表單驗證插件Validation Engine
var v = $("#editPasswordForm").form("validate"); // 先對該表單中的全部輸入框進行校驗(前提:你先要有校驗規則)
// alert(v); // true 或 false
if (v) {
// 說明表單校驗經過
// 再判斷兩次密碼輸入是否一致
var v1 = $("#txtNewPass").val();
var v2 = $("#txtRePass").val();
if (v1 == v2) {
// 說明兩次輸入一致,發送ajax請求,修改當前用戶的密碼
var url = "${pageContext.request.contextPath}/userAction_editPassword.action";
$.post(url, {"password":v1}, function(data) {
// alert(data);
if (data == '1') {
// 密碼修改爲功
$.messager.alert("提示信息", "密碼修改爲功!", "info");
} else {
// 密碼修改失敗
$.messager.alert("提示信息", "密碼修改失敗!", "warning");
}
// 關閉修改密碼的窗口
$('#editPwdWindow').window('close');
});
} else {
// 說明兩次密碼輸入不一致,提示用戶:兩次輸入密碼不一致
$.messager.alert("提示信息", "兩次輸入密碼不一致", "warning");
}
}
});
第三步:在UserAction中提供editPassword方法,用於修改當前用戶的密碼
/*
* 修改當前用戶的密碼
*/
public String editPassword() throws IOException {
User user = (User) ServletActionContext.getRequest().getSession().getAttribute("loginUser");
// 獲取新密碼
String password = model.getPassword();
// MD5加密
password = MD5Utils.md5(password);
user.setPassword(password);
// 此法很差,User的全部字段都要更新,更新的數據太多了
// userServie.update(user); // update t_user set name=?,password=?,...
String flag = "1";
try {
// 使用通用的更新方法
userServie.editPassword(password, user.getId());
} catch (Exception e) {
// 修改密碼失敗
flag = "0";
}
// 響應給瀏覽器一個狀態碼,這種手法經常使用
ServletActionContext.getResponse().setContentType("text/html;charset=UTF-8");
ServletActionContext.getResponse().getWriter().print(flag);
return "none";
}
第四步:在IBaseDao中擴展一個通用的更新方法
IBaseDao.java
// 提供通用修改方法,可變參數
public void executeUpdate(String queryName, Object ...objects);
BaseDaoImpl.java
/*
* 通用更新方法
*/
public void executeUpdate(String queryName, Object... objects) {
// 從本地線程中得到session對象
Session session = this.getSession();
// 使用命名查詢語句得到一個查詢對象
Query query = session.getNamedQuery(queryName);
// 循環爲HQL語句中的?設置值(賦值)
int i = 0;
for (Object arg : objects) {
query.setParameter(i++, arg);
}
// 執行更新
query.executeUpdate();
}
第五步:在User.hbm.xml中定義一個HQL語句,用於修改密碼注意:<query>標籤與<class>標籤同級
<!-- 命名查詢語句 -->
<query name="editPassword">
update User set password=? where id=?
</query>