基础加强(反射)
枚举(了解)
私有化有参和无参的构造方法,用于多选一
enum Grade{
A("90-100"),B("80-90"),C("70-80"),D("60-70"),E("<60");
private String score;
private Grade(String score){
this.score=score;
}
public String toString() {
return "Grade [score=" + score + "]";
}
}
等同于在普通类里进行公有化的new对对象
public static Grade A = new Grade("90-100");
public static Grade B = new Grade("80-90");
public static Grade C = new Grade("70-80");
public static Grade D = new Grade("60-70");
public static Grade E = new Grade("<60");
反射(重点)
概念
java世界里的万物皆对象。
读取类的过程: 由类加载器(ClassLoader)读取class字节码文件,把字节码文件的信息读取进内存,就会被构造成一个Class对象,利用Class对象去构造对象,调用方法,给属性赋值或获取属性值等等操作,这个过程就是反射!!
不通过new获取类对象
Class stu = Class.forName(输入完整包名); //推荐常用
Class stu = Student.class; 类名+class
Class stu = new Student().getClass();
Class对象,代表一个类
getName() //获取完整包名加类名
getSimpleName() //获取类名
getSuperClass() //得到普通父名
getGenericSuperClas() //得到泛型父名
getInterfaces() //得到普通类的接口名
getGenericIntefaces(); //得到泛型接口
getDeclaredConstructor(输入属性名可多个) //没输入就是得到无参,有输入就是得到有参
getDeclareMethod(输入get set方法,输入类型+class) //可以拿到get 、set方法
getDeclareField(输入成员属性名) //可以得到成员属性
Constructor对象:代表一个构造方法
newInstance() 获取构造对象
Method对象: 代表一个普通方法
invoke(obj,参数值) 调用方法
Filed对象:代表一个属性
set(obj,参数) 赋值
get(obj) 获取值
Type 对象:所有类型的公共高级接口
GenericArrayType 数组类型子接口
ParameterizedType 参数类型子接口(常用)
TypeVariable<D> 变量的子接口
WildcardType 通用的子接口
泛型
用处:把运行时异常转化为编译时异常,减少类型转换。
泛型语法
泛型方法(*)
public <T> T method(T t){
}
好处:为了写出通用方法
泛型类/泛型接口
public class Demo<T>{
}
好处:为了减少泛型方法的声明
?: 任意类型,为了保证泛型语法的完整性
extends: 当前类型或者当前类型的子类 向下取
super: 当前类型或者当前类型的父类 向上取
组合使用:(List<? super Number> list)
泛型+反射
getGenericSuperClass() //获取dao的泛型父列:BaseDao<Student>
应用:反射+泛型写出通用代码
//用于抽取业务dao的通用方法
//规则:表名称和类名保存一致(大小写不区别)
public class BaseDao<T> {
private Class targetClass;//需要封装的类型
private String tableName;//需要查询的表名称
//在BaseDao中如何接收泛型类?
public BaseDao(){
//System.out.println(this.getClass());// this: StudentDao 或者TeacherDao
Class clz = this.getClass();//当前运行的dao:StudentDao
Type type = clz.getGenericSuperclass();//获取dao的泛型父列:BaseDao<Student>
ParameterizedType pt = (ParameterizedType)type;//类型转换:转换成参数化类型的子类
Type[] tps = pt.getActualTypeArguments(); // 取出参数化类型的参数:<Student>
targetClass = (Class)tps[0]; // 取出第一个参数: Student.class
//表名
tableName = targetClass.getSimpleName().toLowerCase();
}
QueryRunner qr = new QueryRunner(C3P0Util.getDataSource());
public List<T> findAll(){
try {
return qr.query("select * from "+tableName+"", new BeanListHandler(targetClass));
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public T findById(int id){
try {
return (T)qr.query("select * from "+tableName+" where id=?", new BeanHandler(targetClass),id);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
Struts2框架
struts2概念
struts2是一个基于MVC思想的表现层框架!!!
struts2的底层来源于另一个表现层框架webwork (xwork-core.jar)
struts2是struts1+webwork的整合框架
步骤1)struts2的jar包(最少)
commons-fileupload-1.3.1.jar 【上传组件】
commons-io-2.2.jar 【上传组件】
commons-lang3-3.2.jar 【字符串处理工具类】
freemarker-2.3.22.jar 【freemarker框架包】
javassist-3.11.0.GA.jar 【字节码处理工具类】
ognl-3.0.6.1.jar 【ognl表达式的支持包】
struts2-core-2.3.24.3.jar 【struts2自身的支持包】
xwork-core-2.3.24.3.jar 【wbeworkd框架的支持包】
步骤2)在web.xml中配置struts2的过滤类
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter(在导入包中)
配置内容:
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<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>
步骤3)写一个业务逻辑操作类
Public class XXXX(){
Public String xxx(){
(内容)
}
}
步骤4)写一个struts.xml配置文件(核心)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- struts-default:不要修改 /: 不要修改-->
继承包名需要加后缀分辨
<package name="(任意名字)" extends="struts-default" namespace="/"> //包名
可以用通配符*或*_*
<action name="(任取:路径访问名)" class="(完整包名)" method="(方法名)"> //类名
方法返回名一致 可以多个方法
<result name="success" type="redirect">/index.jsp</result> //方法名
</action>
</package>
</struts>
Struts2执行流程
项目启动:
1)创建StrutsPrepareAndExecuteFilter核心过滤器对象
2)调用StrutsPrepareAndExecuteFilter的init方法
init_DefaultProperties(); 读取default.properties (常量文件)
(or/apache/struts2/default.properties)
init_TraditionalXmlConfigurations() 读取struts的核心xml配置文件
struts-default.xml struts2的默认配置文件 (业务功能的声明)
struts-plugin.xml struts2的插件配置文件
**struts.xml** struts2的核心流程的配置文件(自行修改的)
每次发出请求(访问资源):
1)调用StrutsPrepareAndExecuteFilter的doFilter方法
2)根据用户的请求uri在struts.xml文件的内容匹配对应的action
3)创建一个action配置的class的类对象(Action类对象)
4)调用Action类对象的指定的method方法
5)返回一个视图的字符串
6)根据视图的字符串查找匹配的result
7)跳转到具体的result的路径
解读struts-default.xml
业务功能声明文件
<result-types>
常用的视图类型:
dispatcher: 转发页面
redirect:重定向页面
chain: 转发到Action
redirectAction:重定向到Action (内容写另一个Action的name属性)
stream: 用于文件下载的
</result-types>
拦截器(重要的概念)
在struts.xml配置中如何引用拦截器
<action name="demo" class="cn.itcast.interceptor.ActionDemo" method="admin">
<interceptor-ref name="(打包拦截器名)"></interceptor-ref> //引用打包后的拦截器
<result>/uploe.jsp</result>
</action>
//全局使用拦截器
<default-interceptor-ref name="(打包拦截器名)"></default-interceptor-ref>
拦截器效果类似于过滤器
拦截器 vs 过滤器
过滤器:是servlet的组件,用于过滤请求和响应
拦截器:是struts2的组件,只能用于拦截action
-->
<interceptors>
com.opensymphony.xwork2.interceptor.ParametersInterceptor:参数拦截器
org.apache.struts2.interceptor.FileUploadInterceptor:文件上传拦截器
com.opensymphony.xwork2.interceptor.I18nInterceptor:国际化拦截器
.......
</interceptors>
创建拦截器类一个普通类继承MethodFilterInterceptor也可以继承AbstractInterceptor类
public class HelloInterceptor extends MethodFilterInterceptor{
//执行业务逻辑方法:doIntercept类似Filter的doFilter方法
//ActionInvocation类似Filter的FilterChain
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
System.out.println("1.执行拦截器的前面代码");
/**
* 放行:
* 调用下一个拦截器,或者是目标的action
*/
invocation.invoke();
System.out.println("3.执行拦截器的后面代码");
return null;
}
Struts.xml中配置拦截器(在package包中)
<interceptors>
<interceptor name="(自定义拦截器的名字)" class="(完整包名)"></interceptor> //引用拦截器
<interceptor-stack name="(输入任意拦截器名字)"> //相当于打包拦截器
<!-- 引用拦截器 -->
<interceptor-stackname="defaultStack"></interceptor-ref> //默认18个拦截器
<interceptor-ref name="(与自定义拦截器名字一致才能使用)"></interceptor-ref>
</interceptor-stack>
<interceptors>
Struts2常量配置
Struts2项目启动时加载default.properties常量文件
struts.i18n.encoding: struts2项目中设置的编码
请求:request.setCharacterEncoding("utf-8")
响应: response.setContentType("text/html;charset=utf-8");
struts.multipart.parser: struts2使用的上传组件 (默认jakarta:commons-fileUpload)
struts.multipart.saveDir: 文件上传时缓存目录
struts.multipart.maxSize: 文件上传文件当前请求最大值
struts.action.extension struts2的action访问后缀配置
struts.devMode 是否打印对象信息
struts.enable.DynamicMethodInvocation: 是否开启struts2的动态方法调用机制(默认关闭)
动态方法调用机制,用来简化action的配置,可以使用一个action配置来实现多个方法的调用注意:struts2不推荐开启,因为存在一定的安全漏洞!测试代码的时候可以开启使用!
修改(覆盖)struts常量
在struts.xml配置文件中添加
<constant name=” struts.i18n.encoding” value=”utf-8”></constant>
<!-- 修改struts的UI模块 -->
<constant name="struts.ui.theme" value="simple"></constant> //设置为简单模式把全部el表达式替代成ognl表达式
配置全局视图(包里面,action外面)对当前包下面的所有action起作用的
<global-results>
<result>/succ.jsp</result>
</global-results>
Acation读取参数
1:在方法内私有化需要接收的数据提供get和set的方法,相当于getParameter()方法
private String savePath;
public void setSavePath(String savePath) {
this.savePath = savePath;
}
2:在方法内私有化对象提供get和set方法,jsp页面数据前面必须带对象(常用)
用户名:<input type="text" name="type.name"></br>
密码:<input type="password" name="type.password"></br>
3:方法实现一个ModelDriven<对象名>接口,私有化对象必须new,然后让方法等于对象
private Type types=new Type();
@Override
public Type getModel() {
return types; (返回私有对象)
}
上传图片读取
表单的3 个必要条件
1:<input type="file" name="attach"/>
2:<form enctype="multipart/form-data" method="post"> //post提交 重写enctype
在方法里写出以下私有方法接收,提供get和set方法
private String savePath; //文件传输的过去的地址
public String getSavePath() {
return savePath;
}
public void setSavePath(String savePath) {
this.savePath = savePath;
}
Struts.xml 配置
<param name="savePath">F:/金山打字通/</param> //需要复制过去的地址
//1.接收上传的文件
private File attach; //<input type="file/>的name属性名称
//2.接收文件类型
private String attachContentType; //名称:name属性+ContentType
//3.接收文件名称
private String attachFileName; //名称:name属性+FileName
文件上传细节配置
<!-- 修改文件上传拦截器参数 -->
<interceptor-ref name="fileUpload"> //默认的不能写错
<!-- 修改最大文件大小参数:1M -->
<param name="maximumSize">1048576</param>
<!-- 修改允许的文件类型 -->
<param name="allowedTypes">image/jpeg,image/x-png,image/bmp</param>
</interceptor-ref>
<!-- 必须放在后面,因为先修改了fileUpload文件上传 拦截器的参数,再进行默认拦截器-->
下载文件
Struts.xml中如何配置文件(下载文件全部为配置)
<action name="down" class="gz.itcast.a_down.DownAction" method="down">
<!-- 配置下载视图 :stream-->
<result name={自定义名称}" type="(属性为下载)stream">
<!-- 修改视图的参数 -->
<!-- 下载的文件类型 :设置通用二进制类型-->
<param name="contentType">application/octet-stream(全部格式)</param>
<!-- 下载提示框 ${fileName}:读取Action中的getFileName()方法 -->
<param name="contentDisposition">attachment;filename=${fileName}</param>
<!-- 设置下载的缓存区大小 -->
<param name="bufferSize">512(不改默认1024)</param>
<!-- 需要下载的文件输入流: Action中的getter方法名称 -->
<param name="inputName">fileStream(getInput方法)</param>
</result>
</action>
Action中如何写方法
public class DownAction extends ActionSupport{
//private InputStream fileStream;
private String fileName;
//下载方法
public String down(){
//返回下载视图
return "down";
}
//给struts.xml的inputName配置
public InputStream getFileStream() throws Exception{
File file = new File("E:/图片/1-111119121254.jpg");
fileName = file.getName();
return new FileInputStream(file);
}
//通过getter方法把名称输出给struts.xml文件
public String getFileName() throws Exception{
return URLEncoder.encode(fileName,"utf-8"); //如果图片有中文名字
}
}
国际化(了解)及自定义异常
struts2国际化
原理
com.opensymphony.xwork2.interceptor.I18nInterceptor 国际化拦截器
步骤:
在struts.xml文件中配置国际化资源文件的路径
<!-- 加载国际化资源文件 -->
<constant name="struts.custom.i18n.resources" value="i18n.message"></constant>
在jsp页面使用struts2标签引用国际化文件内容
jsp页面使用: <s:text name="user"/>
action使用: getText("key") (注意:前提Action继承ActionSupport)
自定义异常
包名只能用点
<constant name="struts.custom.i18n.resources" value="cn.itcast.list.message"></constant>
在struts.xml中“input”是报错配置
<result name="input">/actionList.jsp</result>
传输数据给页面
1:使用原生的域对象进行共享
request,session,application
//得到域对象
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
ServletContext application = ServletActionContext.getServletContext();
2:使用三种Map集合共享数据
RequestMap:重新封装了HttpServletRequest
SessionMap: 重新封装了HttpSession
ApplicationMap: 重新封装了ServletContext
ActionContext类:工具类
//先得到ActionContext对象
//RequestMap
ActionContext ac = ActionContext.getContext();
Map requestMap = (Map)ac.get("request");
requestMap.put("r_prods", prods);
//System.out.println(requestMap.getClass());
//SessionMap
Map sessionMap = ac.getSession();
sessionMap.put("s_prods", prods);
//ApplicationMap
Map applicationMap = ac.getApplication();
applicationMap.put("a_prods", prods);
3:通过实现接口的方法使用三种Map集合(推荐)
私有化3个map<String,Object>参数
在Action类上面实现三个接口
RequestAware, SessionAware, ApplicationAware
写出get 和set方法
public class BaseAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{
public Map<String, Object> requestMap;
public Map<String, Object> sessionMap;
public Map<String, Object> applicationMap;
值栈和ognl表达式
值栈
Struts2改变servlet+jsp层:
Action -> 把数据保存到*值栈* -> jsp -> 使用struts2标签+ognl表达式
值栈是struts2存取数据的核心
值栈是一个对象,这个对象实现接口 ValueStack
实现类:OgnlValueStack
值栈分为两个部分:
1:对象栈(Object Stack): ArrayList集合
作用:存放struts2运行过程的action对象,国际化对象.....
2:映射栈(Context (Map) Stack): HashMap集合
作用:存在struts2运行过程的固定的映射数据
存放的映射数据:
key value
===============================
request RequestMap对象(封装request域对象)
session SessionMap对象(封装session域对象)
application ApplicationMap对象(封装context域对象)
parameters ParametersMap对象(封装用户参数数据)
attr AttributeMap对象(封装三个Map集合)
(request : RequestMap
session: SessionMap
application: ApplicationMap)
获取值栈:
struts2框架在运行每个Action的方法前都会创建一个值栈对象。把这个值栈对象放入ActionContext对象中。
运行Action的方法 -> 创建值栈对象 -> 放入到ActionContext对象中 -> 执行代码
ActionContext ac = ActionContext.getContext();
ValueStack vs = ac.getValueStack(); //获取值栈
操作值栈
push(Object o) :压栈
pop(): 推栈
往Action添加一个属性:提供一个getter方法
操作映射栈
ValueStack.getContext().put("key",Object) 往映射栈添加一个元素
操作requestMap
Map rm = (Map)ac.get("request");
rm.put("rm", p);
//2.3 往session元素(SessionMap)添加一个元素
Map sm = ac.getSession();
sm.put("sm", p);
//2.4 往application元素(ApplicationMap)添加一个元素
Map am = ac.getApplication();
am.put("am", p);
ognl表达式
ognl表达式需要借助struts标签:<s:property value="ognl表达式"/>
取对象栈: 不带#号的ognl表达式
查询对象栈的对象顺序:
从栈的指定元素位置开始查询对应,直到栈底(最后一个元素)为止,把所有元素返回。
取某个对象: [0] (取对象栈的第一个元素后面的元素)
取某个对象的属性:[0].name (注意:查询getName()方法)
name 默认就是从第一个元素开始查属性
取映射栈: 带#号的ognl表达式
取映射栈的request的元素:#request.product
取映射栈的session的元素:#session.product
取映射栈的application的元素:#application.product
取映射栈的paraemters的元素:#parameters.product
取映射栈的attr的元素:
#attr.request
#attr.session
#attr.application
Struts标签
Struts逻辑标签
数据标签:
<s:set/> 赋值到值栈中
<s:property/> 从值栈获取数据
条件判断:
<s:if>
<s:elseif>
<s:else>
循环:
<s:iterator> //类似迭代器
Ui类标签
用于简化页面的html输出
表单标签:
<s:form>
<s:textfield/> //就是input输入框 type=”text”
<s:password/> //类似input输入密码type=”password”
<s:radio/>
<s:checkbox/> //存单个的多选框
//可以存集合的多选框(以Map集合存储进去,id键,对象为值)
<s:checkbostlist list="#request.types" name="types" listKey="key" listValue="value.name" value="curTypes"/>
//下拉框
<s:select list="#request.types" listKey="key" listValue="value.name" value="curTypes"/>
Action传输内容
private List curTypes;
public List getCurTypes() {
curTypes = new ArrayList();
curTypes.add(2);
curTypes.add(3);
return curTypes;
}
public void setCurTypes(List curTypes) {
this.curTypes = curTypes;
}
//查询
public String query(){
Map<Integer,Types> types = new HashMap<Integer,Types>();
types.put(1,new Types(1,"图书类"));
types.put(2,new Types(2,"男装"));
types.put(3,new Types(3,"电器类"));
requestMap.put("types", types);
return "tags";
}
表单验证
步骤:
(了解)方法1:Action必须继承actionSupport类,覆盖重写validate方法,里面验证信息和页面数据一致
方法2:配置
把一个验证文件(Action名称-validation.xml)放在对应Action的目录下
内容:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.dtd">
<validators>
<!-- struts2提供了一些常用的属性验证器
requiredstring: 必须填写字符串
regex: 正则表达式
email: 邮箱格式验证器
-->
<!-- field:需要验证的字段 -->
<field name="user.name"> //页面数据
<!-- 属性验证器 -->
<field-validator type="requiredstring">
<!-- 错误发生时,错误提示 -->
<message>用户名必须填写2222</message> //input错误提示语句
</field-validator>
</field>
<field name="user.name">
<!-- 属性验证器 -->
<field-validator type="regex">
<param name="regexExpression">[a-zA-Z0-9]{4,16}</param> //正则
<!-- 错误发生时,错误提示 -->
<message>用户名格式有误:4-16位字母或者数字222</message>
</field-validator>
</field>
<field name="user.email">
<!-- 属性验证器 -->
<field-validator type="requiredstring">
<!-- 错误发生时,错误提示 -->
<message>邮箱必须填写2222</message>
</field-validator>
</field>
</validators>
注意
Xml配置文件的注意事项:
1)Action名称-validation.xml对Action的所有方法生效!
2)如果需要局部验证Action某个方法:Action名称-方法访问名-validation.xml
注意:如果有错误,则调用addFieldError放入错误信息,struts2会自动跳转到input视图
必须在struts.xml配置一个input的视图(否则报错)
<action name="user_*" class="gz.itcast.a_validate.UserAction" method="{1}">
<result>/succ.jsp</result>
*<result name="input">/user.jsp</result>*
</action>
Jsp:页面显示错误信息
<s:fielderror></s:fielderror>
Hibernate框架
Orm 思想(对象关系映射)
关系领域(关系型数据) 对象领域(java)
一张表 一个类
一个字段 类的一个属性
一条记录 一个类的对象
启动步骤
1:导包
1)hibernate的lib里面的required目录的10个jar
2)对应数据库的驱动程序*
2:编写hibernate的启动配置文件(包括数据库连接信息)
在src目录建立一个hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 第一部分:数据库连接信息 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/day31?useUnicode=true&characterEncoding=utf-8</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!-- 2.第二部分:hibernate环境参数配置 -->
<!-- 数据库方言 : hiberbate最终转换成什么数据库的sql语句-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- 3.第三部分:映射文件信息 -->
<mapping resource="gz/itcast/entity/Student.hbm.xml"/> //类似struts2配置
</session-factory>
</hibernate-configuration>
3:编写实体类javabean(必须有无参构造)
4:创建关系型映射文件(通常把 对象.hbm.xml文件放在和实体类同目录)
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping> //底下如果单类名就要加个package="(包名)" 表名
<class name="gz.itcast.entity.Student(完整类名,也可以单类名)" table="t_student">
<!-- 主键配置 -->
<id name="id" column="sid">
<!-- 主键维护策略 :
assigned:程序分配id
-->
<generator class="assigned"></generator>
</id>
<property name="name" column="sname"></property>
<property name="age" column="sage"></property>
</class>
</hibernate-mapping>
5:代码部分(主要获取对象) 可以写一个hibernateUtil.java工具包
//1.获取Session对象
//1.1 加载hibernate.cfg.xml文件
Configuration config = new Configuration().configure();
//1.2 创建一个服务注册器(4.0新特性)
StandardServiceRegistry serviceRegistry =
new StandardServiceRegistryBuilder().applySettings(config.getProperties()).build();
//1.3 创建SessionFactory对象
SessionFactory sessionFactory =config.buildSessionFactory(serviceRegistry);
//1.4 获取一个Session
Session session = sessionFactory.openSession();
//注意:hibernate强制使用事务
//开启事务
session.getTransaction().begin();
执行操作xxxxx
//提交事务
session.getTransaction().commit();
//发生错误回滚事务 try /catch
session.getTransaction().rollback();
注意关闭资源
session.close();
sessionFactory.close();
hibernate.cfg.xml配置
<hibernate-configuration>
<session-factory> -- 连接一个数据库的项目信息
第一部分: 连接参数
<property name="hibernate.connection.driver_class"></property>
<property name="hibernate.connection.url"></property>
<property name="hibernate.connection.username"></property>
<property name="hibernate.connection.password"></property>
第二部分:hibernate环境参数
hibernate.dialect: 数据库方言。为了hibernate适应不同的数据库,方便生成不同数据库 例如:sql语句核心包: org.hibernate.dialect.MySQL5InnoDBDialect
<property name="(写入底下语句)"></property>
hibernate.show_sql: 是否显示执行sql语句(方便测试而已) //值:true
hibernate.format_sql: 是否格式化sql语句(方便测试而已) //值:true
hbm2ddl.auto: 是否需要hibernate维护数据库。默认不维护
值:create: 每次会自动创建表结构
值: update: 每次会更新(先对比)表结构
第三部分:对象关系映射文件
<mapping resource="(hibernate.hbm.xml 完整包名)"/>
*.hbm.xml解读配置(核心)
第一种:配置文件注入
<hibernate-mapping>
package: 类所在的包
<class> -- 代表需要映射一个类
name: 代表映射类名(如果没有配置package,必须写全名)
table: 代表需要映射到的表名
<id name="(实体ID)" column="(对应表单ID)"> 代表主键配置
<generator class="assigned"> 主键维护策略
<property name=”属性名称” column=”字段名称” length=”字段长度”> 代表普通属性映射
第二种:注解注入(常用)
Hibernate注解
概念:
hibernate注解是代替xml配置的另一个参数配置方案
步骤:
1:在实体类指定位置上指定注解
2:在hibernate.cfg.xml加入映射类 <mapping class="gz.itcast.b_annotation.Product(实体类)"/>
常见注解:
@Entity 声明当前类是一个映射类 (如果需要映射的类必须加)
@Table(name="t_product", indexes={@Index(columnList="NAME", name="IDX_USER_NAME")}(增加索引值在查询时会比较快)) 声明表名 (可以省略不写,表与实体属性名一致)
@Table(name="OA_ID_USER(表名)", indexes={@Index(columnList="NAME", name="IDX_USER_NAME")})
@Id 声明主键
+@GeneratedValue(strategy=GenerationType.AUTO)(可以选择谁负责增长AUTO代表自动选择) 声明注解维护策略 默认数据库生成id值
@Column(name="p_id",length=”指定字段长度”) 声明字段名
@OneToMany(cascade={CascadeType.ALL},mappedBy="user") 一对多
@ManyToOne(fetch=FetchType.LAZY(是否延迟加载,必须填), targetEntity=User.class(关联的实现化类)) 多对一
+@JoinColumn(name="MODIFIER(取外键列的列名)", referencedColumnName="USER_ID(引用主表的那个主键列名)", foreignKey=@ForeignKey(name="FK_DEPT_MODIFIER")(更改外键约束名,不写的话自动生成))
@JoinColumn(name="MODIFIER", referencedColumnName="USER_ID",
foreignKey=@ForeignKey(name="FK_DEPT_MODIFIER"))
@ManyToMany(fetch=FetchType.LAZY(懒加载), targetEntity=Role.class(需要引用的实习化类), mappedBy="users(中间表由角色来维护,没加代表自己维护)") 多对多
+@JoinTable(name="OA_ID_USER_ROLE(多对多需要生成外表,外表的名字)", joinColumns=@JoinColumn(name="ROLE_ID(没有加mappedBy的列名)", referencedColumnName="ID(需要关联的主键id)"), inverseJoinColumns=@JoinColumn(name="USER_ID(加了mappedBy的列名)", referencedColumnName="USER_ID(需要关联的主键id)"))
@JoinTable(name="OA_ID_USER_ROLE", joinColumns=@JoinColumn(name="ROLE_ID", referencedColumnName="ID"), inverseJoinColumns=@JoinColumn(name="USER_ID", referencedColumnName="USER_ID"))
@OneToOne 一对一
@Temporal(TemporalType.TIMESTAMP)指定数据库为时间格式,TIMESTAMP(年月日时分秒)
Session对象基本CRUD操作
1:保存save
session.save(放入存储的对象)
2:修改数据get拿set直接改
Product p = (Product)session.get(Product.class, 2); //对象.class和对应ID号
修改数据
p.setName("iphone6s");
3:查询get数据
Product p = (Product)session.get(Product.class, 1); //get一调用就执行
Product p = (Product)session.load(Product.class, 1); //调用不执行,需要才执行
Hql语句
List<Product> list = session.createQuery("from Product p").list();
for (Product product : list) {
System.out.println(product);}
4:删除delete
Product p = new Product();
p.setId(1);
session.delete(p);
方式二:(推荐)
Product p = (Product)session.get(Product.class, 1);
if(p!=null){
session.delete(p);
}
主键维护策略
<generator class="assigned"></generator>
开发者:
assigned 开发者自觉给
数据库:(类型必须是int或Integer)
identity 利用自增长策略,只能用在mysql或者sql server
sequence 利用序列增长策略,只能在oracle或者db2
*native (推荐)自动根据具体的数据库增长策略,选择最优的一个
hibernate:
*increment:hibernate的自增长策略 (每次先查表的最大id值,然后+1)(int)
uuid: hibernate提供的uuid算法策略 (String)
hibernate.hbm.xml映射不同类型
type="integer"
hibernate类型 java类型
*整数 int/integer java.lang.Integer
*小数 double java.lang.Double
*字符 string java.lang.String
*日期 date java.util.Date
字符文件 text java.lang.String
字节文件 binary byte[]
集合映射
Set集合映射
<set name="实体类set名" table="对应表名">
<!-- 外键 -->
<key column="uid"></key> //外键的id
<!-- 集合里面元素的字段 -->
<element column="address" type="string"></element> //string小写
</set>
List集合映射
<list name="实体类set名" table="对应表名">
<!-- 外键 -->
<key column="uid"></key>
<!-- 排序索引自动 -->
<index column="任意名"></index>
<element column="任意名" type="string"></element>
</list>
Map集合映射
<map name="实体类set名" table="对应表名">
<!-- 外键 -->
<key column="uid"></key>
<!-- map的key字段 key值,map主键 -->
<map-key type="string" column="任意名"></map-key>
<!-- map的value字段 -->
<element column="任意名" type="string"></element>
</map>
对象关系映射
一对多单向
例子
对象:这个对象有其他对象信息 这个没有
class User{ class Address{
int id; int id;
String name; String name;
int age; String zipcode;
*Set<Address>* String phone;
String address;
}
Hibernate.hbm.xml配置映射
<!-- set对象集合(一对多) -->
<set name="实体类set集合名字">
<!-- 外键 -->
<key column="uid"></key>
<!-- set集合元素:Address对象 -->
<one-to-many class="gz.itcast.c_one2many_single.Address(完整全名)" />//一对多关键语句
</set>
级联映射 在set里加个cascade="all " 全部自动更新
<set name="实体类set集合名字" cascade="all ">
save-update: 当保存/更新会员(User)的数据时,同时保存/更新起关联的收货地址
delete : 当删除会员(User)的数据时,同时删除起关联的收货地址(Address)对象
all: save-update + delete
多对一单向
对象: 这没有外面实体信息 关联了外面实体信息
class User{ class Address{
int id; int id;
String name; String name;
int age; String zipcode;
String phone;
String address;
*User user;*
}
Hibernate.hbm.xml配置映射
<many-to-one name="实体名user" class="gz.itcast.many2one_single.User(完整包名)"
column="uid(另个实体id值)" cascade="all" (自动)></many-to-one>
一对多及多对多双向
一对多(多对一)双向
<!-- 一对多集合映射 -->
<set name="(set实体名) " cascade="all" inverse =”true”>
<!-- 外键 -->
<key column="(外键字段)"></key>
<one-to-many class="gz.itcast.a_many2one_double.Address(对多的对象)"/>
</set>
<!-- 多对一配置
column: 值和一对多的key保持一致!!
-->
<many-to-one name="user(一对多的对象)"
class="gz.itcast.a_many2one_double.User(对一的对象)"
column="uid(一对多的Key值)"
cascade="all"/>
多对多双向(相当于重新建立一个关系表)
inverse: 是否需要反转关系的维护权
false: 不反转,由当前方维护
true:需要反转,由对方维护
hibernate在一对多的关心中,默认由一方维护(inserse="false"),为了提高效率(节省了update语句),可以把一方的insevse设置为true,把维护权给多方。
Student表
<set name="(set实体名) " table="student_teacher(建立的关系表)" cascade="all" inverse="true">
<!-- 当前方在关系表的外键 -->
<key column="sid(当前表首字+id,关系表里的字段)"></key>
<!-- set元素
class: set集合的元素的类型
column: set元素的表在关系表的外键
-->
<many-to-many class="gz.itcast.b_many2many_double.Teacher(关联的表)" column="tid(关联表的key值)"></many-to-many>
</set>
Teacher表
<set name="(set实体名)" table="(关系表一致)">
<key column="tid(关系表里的id字段)"></key>
<many-to-many class="gz.itcast.b_many2many_double.Student(关联的表)" column="sid(关联表的key值)"></many-to-many>
</set>
一对一双向
<!-- 一对一的主键关联配置:一对一配置
constrained: 是否把主键设置为外键
false:否
true: 是
-->
例如:一人对一身份证
<one-to-one name="idcard"
class="gz.itcast.c_one2one_double.IdCard"
cascade="all"/>
<!-- 一对一的主键关联配置:一对一配置
constrained: 是否把主键设置为外键
false:否
true: 是
-->
<one-to-one
name="person"
class="gz.itcast.c_one2one_double.Person"
constrained="true"></one-to-one>
hibernate查询(hql语句)
全表查询返回list集合 from (对象名)
指定字段查询 默认情况下,返回一个List<Object[]>需要遍历两次才能拿数据,可以封装成List<Employee>,在Employee里有参构造(有参的值写需要返回封装的对象属性)
select e.(对象属性),e.(对象属性) from (对象名) e(自定义别名)
条件查询返回list
from (对象名) e(自定义别名) where e.(对象属性)=? and e.(对象属性)=?
设置属性?
q.setParameter(0, "李_");
q.setParameter(1, 6500.0);
from (对象名) e(自定义别名) where e.(对象属性) like ? //like模糊查询
q.setParameter(0, "%李%"); //%表示省略前后
查询排序返回list 排序: order by asc: 升序 desc : 降序
from (对象名) e(自定义别名) order by e.(对象属性) asc
聚合查询返回一个对象(max,min avg,count...)
select max(e.对象属性) from (对象名) e(自定义别名)
统计查询可以设置约束条件(变成分页查询)返回int值
select count(e) from (对象名) e(自定义别名)
设置分页
q.setFirstResult(0); //起始位置
q.setMaxResults(3); //查询条数
分组查询 (group by)
select e.(对象属性1),count(*) from (对象名) e(自定义对象别名) where e.(对象属性1) is not null and e.(对象属性1)<>'' group by e.(对象属性1)
分组后筛选(having)
select e.(对象属性1),count(*) from (对象名) e(自定义对象别名) where e.(对象属性1) is not null and e.(对象属性1)<>'' group by e.(对象属性1) having count(*)>2(条件)
多表查询 内连接(inner join) 外右连接(right outer join)
(内连接)select e.name,e.dept.deptName from (对象名) e(自定义对象别名) inner join e.dept
(外右连接) select e.dept.deptName,e.name from (对象名) e(自定义对象别名) right outer join e.dept
原生sql查询
SQLQuery sq = session.createSQLQuery("select * from employee"); //原来sql语句表名
//封装成什么对象
sq.addEntity(Employee.class);
List<Employee> list = sq.list();
注意:如果该查询需要比较高的性能要求,可以使用sql查询
细节
一级缓存
概念
一级缓存,也称之为Session级别的缓存,在Session对象内部设计的一个缓存,只能在Session范围内使用。
默认情况下,一级缓存是打开和使用,我们不能关闭它。
操作一级缓存
1:session.flush() 同步一级缓存的数据 (经常跟第3一起用,刷完内存里东西,然后删除内存对象)
2:session.evict(obj) 从一级缓存清除某个对象
3:session.clear() 清空一级缓存的所有对象
Hibernate对象状态
临时状态
例如: Student stu=new Student() 新new对象
不在一级缓存中
数据库找不到对应记录
持久对象
例如:Admin admin = session.get(Admin.class, 1); 从session中直接取出来的数据
在一级对象中
数据库找得到对应记录
游离对象
例如:Student s = (Student) session.get(Student.class, 1); // s:持久对象 session.evict(s);//删除一级缓存里的数据
不在一级缓存中
游离对象的数据和数据库的数据保持一致,但是不能用于任何修改操作
删除对象
例如:Student s = (Student) session.get(Student.class, 3); // s:持久对象 session.delete(s);
不在一级缓存中
数据库数据不一致
延迟加载
get和load的区别
get
(1)Get方法执行后立即查询数据库数据,返回数据库数据(真实对象)
(2)get方法如果查询数据库没有对应数据时,返回null
Load
(1) load方法执行之后,没有查询数据库(返回的是一个代理对象),而是在使用对象的属性数据
(2) load方法如果查询数据库没有对应数据时,返回ObjectNotFound异常
延迟加载
<!-- lazy: 延迟加载。默认情况下就是延迟加载 -->
<set name="addresses" cascade="all" lazy="true">
<key column="sid"></key>
<one-to-many class="gz.itcast.d_lazy.Address"/>
</set>
二级缓存
步骤1:导入二级缓存的jar包
ehcache-core-2.4.3.jar
hibernate-ehcache-4.3.8.Final.jar
slf4j-api-1.7.2.jar
slf4j-log4j12-1.7.2.jar
步骤2:配置开启二级缓存(hibernate.cfg.xml).
<!-- 启用二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 引入二级缓存插件(提供者) -->
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<mapping xxxx/> //需要引用的二级缓存必须放在mapping后面
<!-- 把指定类使用二级缓存 -->(可以使用注解在实体类上写入@Cache(usage=CacheConcurrencyStrategy.READ_WRITE))
<class-cache usage="read-write" region="itCache" class="gz.itcast.d_lazy.Address(需要二级缓存的实体)"/>
步骤3:提供配置文件.
src/ehcache.xml
配置查询缓存(效果不大)
-- 提高查询速度.(二级缓存的基础之上).
缓存的是查询语句.
-- 配置开启查询缓存(hibernate.cfg.xml).
<!-- 配置开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>
-- 指定哪些查询语句做缓存.
getSession().createQuery(hql).setCacheable(true);
连接池插件(c3p0)
1: 导入c3p0插件包 optional\ehcache\(hibernate的lib包中)
c3p0-0.9.2.1.jar
hibernate-c3p0-4.3.8.Final.jar
mchange-commons-java-0.2.3.4.jar
2: 在hibernate.cfg.xml配置
<!-- 使用c3p0插件 -->
<property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
<property name="connection.url">jdbc:mysql://localhost:3306/day34?useUnicode=true&characterEncoding=utf-8</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!-- 初始连接数 -->
<property name="c3p0.min_size">5</property>
<!-- 最大连接数 -->
<property name="c3p0.max_size">20</property>
<!-- 等待时间 -->
<property name="c3p0.timeout">3000</property>
Spring框架
概念
spring是一个JavaEE应用程序的一站式(full-stack)框架,是一个轻量级的*IOC*和*AOP*的容器框架,主要用于解决应用中javabean对象的生命周期管理和对象之间的依赖关系问题,还可以整合其他如struts2,hibernate等框架,简化这些框架的使用。
Spring的 IOC
设计一个beanFactory(实例工厂)解决项目管理问题
Spring IOC开发步骤
1:导入jar包
commons-logging-1.1.1.jar
spring-beans-4.2.0.RELEASE.jar
spring-context-4.2.0.RELEASE.jar
spring-core-4.2.0.RELEASE.jar
spring-expression-4.2.0.RELEASE.jar
2:编写一个类
public class UserDao {
public void save(){
System.out.println("userDao.save()....");
}
}
3:在src目录里建立一个applicationContext.xml (或者beans.xml或者sprirng.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用springIOC工厂创建一个对象 -->
<bean id="userDao" class="gz.itcast.a_hello.UserDao"></bean>
</beans>
4:获取对象
//使用类路径方式读取spring的xml文件
ApplicationContext ac =
new ClassPathXmlApplicationContext("/gz/itcast/a_hello/applicationContext.xml");
//2.从springIOC工厂中获取一个对象
UserDao userDao = (UserDao)ac.getBean("userDao");
等同于UserDao user =new UserDao
SpringIOC的简介
springIOC,主要解决的是对象管理问题,以及对象之间的依赖关系问题!!!!
IOC, Inversion Of Control 控制反转 (解决对象创建问题)
没有IOC:new Student() 直接获取一个对象 依赖性太强,耦合性太大
有IOC: getBean("xxx") 把对象的控制器托管给BeanFactory(springIOC)
DI,dependency injection 依赖注入 (解决对象之间的依赖关系问题)
没有DI: IUserDao usrDao = new UserDao()
有DI: IUserDao userDao;
public void setUserDao(IUserDao userDao){
this.userDao = userDao;
}
对象创建问题(IOC)
使用无参构造方法创建对象
<bean id="userDao1" class="gz.itcast.a_hello.UserDao"></bean>
注意:
在给对象提供了有参的构造方法的同时,不要忘记补上一个无参构造方法
使用有参构造方法创建对象
<!-- 使用有参构造方法创建对象 -->
<bean id="userDao" class="gz.itcast.b_bean.UserDao">
<constructor-arg index="0" value="狗娃"></constructor-arg>
<constructor-arg index="1" value="20"></constructor-arg>
</bean>
使用工厂类创建对象
成员方法
<!-- 使用工厂类的成员方法来创建对象 -->
<!-- 1.1 创建工厂类对象 -->
<bean id="factory" class="gz.itcast.b_bean.ObjectFactory"></bean>
<!-- 1.2 调用工厂类的成员方法 -->
<bean id="userDao2" factory-bean="factory" factory-method="getInstance"></bean>
//工厂类
public class ObjectFactory {
//成员方法
public UserDao getInstance(){
return new UserDao("张三",22);
}
}
静态方法
<!-- 使用工厂类的静态方法来创建对象 -->
<bean id="userDao3" class="gz.itcast.b_bean.ObjectFactory" factory-method="getStaitcInstance"></bean>
//工厂类
public class ObjectFactory {
//静态方法
public static UserDao getStaitcInstance(){
return new UserDao("李四",24);
}
}
单例和多例问题
scope
single: 单例
prototype:多例
<bean id="userDao4" class="gz.itcast.b_bean.UserDao" scope="prototype"></bean>
是否延迟创建对象
lazy-init 是否需要延迟创建对象,默认fales,改成true就是延迟创建
default-lazy-init="true": 设置全局的延迟创建bean
注意:lazy-init只对单例(singleton)起作用
依赖注入
1:构造方法注入
<bean id="user" class="gz.itcast.c_di.User">
<constructor-arg index="0" value="狗娃"></constructor-arg>
</bean>
构建有参构造
public User(String name){
System.out.println("name="+name);
}
2:使用set方法注入数据(推荐)
类里面提供set方法
<bean id="user" class="gz.itcast.c_di.User">
<!-- name: set方法名称 例如setAge()的set方法名称:age-->
<property name="age" value="20"></property>
</bean>
注入不同的数据类型:
*String类型:<value>
*int类型: <value>
*double类型: <value>
数组类型:
<array>
<value>广州天河</value>
<value>广州番禺</value>
<value>广州越秀</value>
</array>
List类型:
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
Map类型:
<map>
<entry key="key1" value="value1"/>
<entry key="key2" value="value2"/>
<entry key="key3" value="value3"/>
</map>
*Properties类型:
<props>
<prop key="pro1">value1</prop>
<prop key="pro2">value2</prop>
<prop key="pro3">value3</prop>
</props>
*引用类型:
<property name="addr" ref="addr"></property>
SpringIOC注解(重点)
1:导入spring的aop的jar包
spring-aop-4.2.0.RELEASE.jar
2:在applicationContext.xml引入context名称空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
3:使用context的标签去扫描注解目录
<context:component-scan base-package="gz.itcast.d_annotation"></context:component-scan>
4:注解用法
//@Component("user")等价于 <bean id="user" class="gz..xxxx.User"/>
@Controller("user")
public class User {
@Resource(name="addr") //name输入对象@Component的值
private Address addr;
// 类似于<property name="addr" ref="addr"/>,不同于property注入的是,@Resource使用的是 暴力反射直接注入属性
<!-- 开启annotation实现字段注入 @Resource -->
<context:annotation-config/>
@Resource // byType
@Resource(name="jobDao") // byName
private JobDao jobDao;
常用的注解:
@Component("xxx") 在springIOC工厂中创建一个对象(底下3个效果等同,为了区分)
@Resource("xxx") 在当前对象中注入springIOC工厂中的一个对象
@Repository 作用同@Component; 在持久层使用
@Service 作用同@Component; 在业务逻辑层使用
@Controller 作用同@Component; 在控制层使用
SpringAop
springAOP概念
AOP,Aspect Object Programing 面向切面编程,主要是用于分离核心业务代码 和 服务代码(重复代码)
三种代理方式
1:静态代理 (关键:手写代理类,要求:必须实现接口)
写一个方法类接口
public interface IUserDao {
public void save();
public void update();
}
public class UserDaoProxy implements IUserDao{
private IUserDao userDao;
//绑定目标对象
public void bind(IUserDao userDao){
this.userDao = userDao;
}
@Override
public void save() {
System.out.println("开启事务"); //代理类实现接口后可以修改属性
//执行核心业务:
userDao.save();
System.out.println("提交事务");
}
@Override
public void update() {
System.out.println("开启事务");
//执行核心业务:
userDao.update();
System.out.println("提交事务");
}
}
2:jdk动态代理
//可以生成任意对象的代理类对象的工具
public class ProxyFactory {
private Object target;
//绑定被代理对象
public void bind(Object target){
this.target = target;
}
//生成一个被代理对象的代理类对象
public Object getProxyInstance(){
return Proxy.newProxyInstance(
ProxyFactory.class.getClassLoader(), // 指定类加载器,随意指定
target.getClass().getInterfaces(), // 指定代理类实现的接口(通常和被代理对象相同的接口)
new InvocationHandler() { //new一个内部类,指定代理后的处理程序
@Override //生成的代理对象 //当前方法的参数
public Object invoke(Object proxy, Method method, Object[] args) // invoke()执行处理程序
throws Throwable {
System.out.println("当前执行的方法:"+method.getName());
//目标: 在每个业务方式执行事务代理
System.out.println("开启事务");
//执行核心业务方法
Object result = method.invoke(target, args);
System.out.println("提交事务");
return result;
}
}
); // 指定代理后的处理程序 (代理后要怎么做???);
}
}
3: CGLIB子类代理方式
关键:不需要实现接口,直接生成目标对象的子类代理
步骤:
导入cglib的jar包
spring-core包
spring-aop包
编写生成子类对象的程序
//生成子类代理对象的工厂类
public class ProxyFactoryCGLIB implements MethodInterceptor{
private Object target;
//绑定目标对象
public void bind(Object target){
this.target = target;
}
//生成目标的子类代理对象
public Object getProxyInstance(){
//1.创建工具类
Enhancer en = new Enhancer();
//2.指定父类
en.setSuperclass(target.getClass());
//3.指定回调函数(底层实现需要类加载器)
en.setCallback(this);
//4.创建子类代理对象
return en.create();
}
/**
* proxy: 子类代理对象
* method: 当前调用的方法
* value: 当前调用的方法的参数
* mp: 当前方法的代理对象
*/
@Override
public Object intercept(Object proxy, Method method, Object[] value,
MethodProxy mp) throws Throwable {
System.out.println("开启事务");
//调用核心业务:
Object result = method.invoke(target, value);
System.out.println("提交事务");
return result;
}
}
SpringAOP实现
SpringAOP底层使用CGLIB子类代理方式实现
SpringAOP关键词:
连接点(jointPoint):需要关注的核心业务方法( save() update() )
切入点(pointcut):需要切入服务代码的业务方法 ( save())
注意:
1)切入点一定是连接点
2)连接点不一定是切入点
通知(advice):
需要在切入点上面执行的代码逻辑
*切面(aspect/advisor):
切入点+通知 : 在某些方法(切入点)执行通知代码
导入jar包
spring-core
spring-aop
1:编写目标对象(专注核心业务)
public class UserDao {
public void save(){
System.out.println("保存数据");
}
public void update(){
System.out.println("更新数据");
}
}
2:编写切面类,里面写不同类型的通知
public class MyAspect {
//定义通知
/**
* 前置通知(在业务方法前面切入)
* 后置通知(在业务方法后面切入)
* 环绕通知(在业务方法前后切入))
*/
public void before(){
System.out.println("执行前置通知");
}
}
3:配置切面
<!-- 创建目标对象 -->
<bean id="userDaoID" class="gz.itcast.dao.UserDao"></bean>
<!-- 创建切面对象-->
<bean id="myAspect" class="gz.itcast.dao.MyAspect"></bean>
<!-- 定义切面配置 -->
<aop:config>
<!-- 定义一个切面 -->
<aop:aspect ref="myAspect(切面类id)">
<!-- 通知 -->
<!-- 前置通知 -->
<!-- 切入点 -->
<aop:pointcut id="myptID(自定义ID)" expression="execution(*(通配方法修饰符,方法返回值) gz.itcast.dao.UserDao.*(通配任意方法名)(..)(两个点省略全部参数))" />
<!-- 切面类中的方法名称 -->
<aop:before method="before(插入的方法)" pointcut-ref="myptID(写入切面ID)"/>
</aop:aspect>
</aop:config>
Spring整合hibernate事务
<!-- 创建一个spring提供Hibernate的事务管理器 : 用于管理每次操作的事务代码-->
<bean id="hbmTxID" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<!-- 必须注入SessionFactory -->
<property name="sessionFactory" ref="sfID"/>
</bean>
<!-- 事务通知 : 环绕通知-->
<!--
id: 事务通知的标记
transaction-manager: 事务管理器
-->
<tx:advice id="txID" transaction-manager="hbmTxID">
<!-- 事务属性 -->
<tx:attributes>
<!-- propagation: 事务传播属性
REQUIRED: 如果上一个方法有事务,则加入上个方法的事务,如果没有,则新建一个事务。 通常更新方法设置为这个属性
SUPPORTS:如果上个方法有事务,则加入事务,如果没有,则不加入事务。通常查询方法设置这个属性
-->
<tx:method name="set*" read-only="true"/> : 代表没开启事务,只能做查询.
<tx:method name="set*" read-only="false"/> : 代表开启了事务,CURD都可以做.
<tx:method name="save" propagation=" SUPPORTS "/>//可以指定方法
<tx:method name="*" propagation=" REQUIRED "/>//通配全部方法
</tx:attributes>
</tx:advice>
<!-- 配置切面 -->
<aop:config>
<!-- 切入点 -->
<aop:pointcut id="myptID" expression="execution(* gz.itcast.dao.UserDao.save(..))" />
<!-- 切面 -->
<aop:advisor advice-ref="txID" pointcut-ref="myptID"/>
</aop:config>
注意事项:
1:如果使用了spring的事务管理,则在Dao中自行获取Session时,必须使用getCurrentSession()方法
2:也可以是spring提供的HibernateTemplate工具类模板
在Dao中写用private HibernateTemplate ht;替换private SessionFactory sf;
<bean id="hbmTempID" class="org.springframework.orm.hibernate4.HibernateTemplate">
<property name="sessionFactory" ref="sfID"/>
</bean>
常见方法:
ht.save()
ht.update()
ht.get()
ht.find("hql",Object... value); 相当于createQuery(“hql”).setParameter(0,value)
ht.execute(); 使用回session对象
(重点)步骤:
1.事务管理器: HibernateTarnsactinManager
2.通知: tx:advice
3.切入点: point-cut
4.切面: <advisor advice-ref="通知" pointcur-ref="切入点"/>
String整合Struts2
在web.xml启动struts2和spring容器
<!-- 启动struts2 -->
<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>
<!-- 启动spring容器 :ContextLoaderListener用于启动spring的容器-->//相当于监视器
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
关键: 创建struts2中使用到的Action对象
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 创建struts2的Action对象
scope="prototype": action必须是多例的
-->
<bean id="userActionID(两边要一致)" class="gz.itcast.action.UserAction" scope="prototype">
<property name="userService" ref="userServiceID"/>
</bean>
</beans>
在struts.xml文件引用spring容器的对象
<package name="user" namespace="/" extends="struts-default">
<action name="user_*" class=" userActionID(两边要一致)" method="{1}">
<result>/succ.jsp</result>
</action>
</package>
Spring记录日志
第一种
1:写一个类与数据库对应值一致:
2:写一个util工具类,记录进入用户的操作。
//系统日志工具类
public class LogUtil {
//注入日志业务类
private ISystemlogService systemlogService;
public void setSystemlogService(ISystemlogService systemlogService) {
this.systemlogService = systemlogService;
}
//写日志
public void writeLog(JoinPoint jp){ //JoinPoint:连接点
Object target = jp.getTarget();//目标对象
String calledClassName = target.getClass().getName();//目标类的类名
String calledMethodName = jp.getSignature().getName();//调用的方法名
String func = calledClassName+":"+calledMethodName;//操作名称
if(target instanceof ISystemlogService){//遇到日志业务,则退出
return;
}
Systemlog log = new Systemlog(); //创建记录对象
//操作者:当前登录的用户
Employee operator = (Employee)ActionContext.getContext().getSession().get("loginInfo");
log.setOperator(operator);
log.setOptTime(new Date());
log.setFunc(func);
//获取ip
String ip = ServletActionContext.getRequest().getRemoteHost();
log.setIp(ip);
systemlogService.save(log); //调用service保存方法
}
}
3:spring的aop配置
<!— 需要插入的类配置 -->
<bean id="logUtil" class="gz.itcast.crm.util.LogUtil">
<property name="systemlogService" ref="systemlogService"/>
</bean>
<!-- 系统日志切面 -->
<aop:config>
<aop:aspect ref="logUtil">
<!-- 切入点 -->
<aop:pointcut id="logpt" expression="execution(* gz.itcast.crm.service.impl.*.*(..))" />
<!-- 通知 -->
<aop:after method="writeLog" pointcut-ref="logpt"/>
</aop:aspect>
</aop:config>
第二种
aop日志切面.
-- 记录业务层方法执行的速度(效率).
-- 记录业务层方法的异常信息.
commons-logging-xxx.jar: 只是在控制台输出日志信息.
private Log logger = LogFactory.getLog(LogAdvice.class);
提供日志文件来记录日志.
log4j框架:
logging for java : apache组织.
log4j-1.2.17.jar
/** 定义日志记录器对象 */
private Logger logger = Logger.getLogger(LogAdvice.class);
logger.info(message);
logger.debug(message);
logger.error(message);
log4j.properties: 属性文件://设置存储路径
第一个部分:
log4j.rootLogger = info,a,b
log4j.rootLogger = [日志级别],输出端1,输出端2
第二个部分:
log4j.logger.com.opensymphony.xwork2=error
log4j.logger.包名=日志级别
第三个部分(输出端):
org.apache.log4j.ConsoleAppender:将日志信息输出到控制台.
org.apache.log4j.DailyRollingFileAppender:
将日志信息输出到一个日志文件,并且每天输出到一个新的日志文件.
6. slf4j框架:
simple logging fade for java : java的日志门面(日志规范).
<!-- 日志切面 -->
<bean id="logAdvice" class="cn.itcast.oa.core.aop.LogAdvice"/>
<!-- 切面(aop) -->
<aop:config>
<!-- 配置切入点 (切业务层) -->
<aop:pointcut expression="execution(* cn.itcast.oa.*.*.service.impl.*.*(..))" id="pointcut"/>
<!-- 事务切面将上面的声明式事务配置 txAdvice 运用到 哪个切入点pointcut -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
<!-- 配置日志切入 -->
<aop:aspect ref="logAdvice">
切入方法
<aop:around method="around" pointcut-ref="pointcut"/>
配置异常后切入
<aop:after-throwing method="error" pointcut-ref="pointcut" throwing="e"/>
</aop:aspect>
</aop:config>