本帖最后由 小石姐姐 于 2018-7-17 13:56 编辑
struts2 引入步骤:
1.导入jar(13个)
2.在web.xml配置过滤器(StrutsPrepareAndExecuteFilter)
3.配置struts.xml(action中有name, class, method属性,
分别代表访问路径,类全名,类中方法名)
4.创建Action(写逻辑)
解决:1.在Action中得到请求参数
声明name属性,并提供get/set方法.
2.实现路径跳转
1.给Action添加String返回值
2.在struts2中action标签中添加<result name="">标签.
name是Action中return的返回值.result中是路径.
eclipse导入本地dtd文件
eclipse导入本地xsd文件
xml(可扩展标记语言)
1.数据存储(不用,数据库)
2.作为数据协议进行传输(xml/json)
3.配置文件
约束:dtd约束,schema约束
区别1. .dtd/.xsd
2. schema约束支持命名空间
配置文件加载顺序:
[AppleScript] 纯文本查看 复制代码 *1.default.properties声明常量
*2.struts-default.xml(默认配置)声明interceptor result bean
*struts-plugin.xml 插件配置声明
*strtus.xml用于struts2(自定义配置)框架的配置
3.struts.properties定制常量
4.自定义配置提供
5.web.xml
6.bean相关配置
获取Servlet API
1.通过ServletActionContext静态方法获取
[AppleScript] 纯文本查看 复制代码 ServletActionContext.getRequest()
ServletActionContext.getResponse()
ServletActionContext.getServletContext()
2.采用注入方式,实现interceptor中servletConfig参数中的接口
[AppleScript] 纯文本查看 复制代码 ServletRequestAware
ServletResponseAware
ServletContextAware
Action如何接收前台页面的参数
a)属性 提供get/set方法
b)对象 提供对象,get/set方法 前台页面使用ognl 对象.属性
c)模型驱动 ModelDriven 提供一个实例对象 实现getModel()方法,把实例对象进行返回
d)使用servlet相关api获取
ServletActionContext.getRequest().getParameter()
ognl:
<%@ taglib prefix="s" uri="/struts-tags"%>
<s:property value=""/>
从根中获取,不需要加#
从非根中获取,需要加#
valueStack内部有root和context,它们分别是ArrayList和Map
root中主要存储action的相关数据
context中主要存储parameters,request,session,application的引用
获取ValueStack:
1.通过request对象来获取.(ValueStack保存在request中)
ValueStack vs=(ValueStack)ServletActionContext.getRequest().getAttribut(
ServletActionContext.STRUTS_VALUESTACK_KEY);
2.使用ActionContext获取.
ValueStack vs=ActionContext.getContext().getValueStack();
向ValueStack中存储数据:(都是向root中存储)
valueStack.push("hello");
valueStack.set("username","tom");
request,action,actionContext,valueStack之间的关系:
每一个请求访问一个action,action是多例,每一个action对应一个actionContext,
每一个请求对应一个valueStack,valueStack中存放action对象和modelDriven中的Bean(如果实现的modeDriven接口),
valueStack保存在request中.
request-ActionContext-Action-ValueStack都对应一次请求(一个线程)
Ognl中的特殊字符:
#:从非root中获取数据
%:强制解析ognl表达式
$:在配置文件中获取valueStack中的数据
Interceptor拦截器:
Struts执行过程:
当发送请求访问Action时,会被StrutsPrepareAndExecuteFilter监听器拦截,
在监听器中采用动态代理方法加载struts.xml配置文件,对所有的interceptor进行遍历,每一个拦截器又采用递归.
自定义拦截器:(使用自定义拦截器时,必须添加默认的拦截器)
1.实现Interceptor接口 (对所有方法都拦截)
<interceptors>
<interceptor name="myInterceptor" class=""/>
<interceptor-stack name="myStack">
<interceptor-ref name="myInterceptor"/>
<interceptor-ref name="defaultStack"/> // 添加默认拦截器
</interceptor-stack>
</interceptors>
可以在action标签中为特定的Action添加拦截器:
<action>
<interceptor-ref name="myStack">
</action>
2.继承MethodFilterInterceptor (对指定方法拦截)
<interceptor name="myInterceptor" class="">
<param name="includeMethods">showProduct</param>
<param name="encludeMethods">addProduct</param>
</interceptor>
文件上传:
1.重要三点:表单method="POST",enctype=""multipart/form-data,<input type="file" name="upload">,
2.对应的action中提供三个属性和get/set方法:
private File upload; // 名称要与表单中<input>的name属性一致
private String uploadContentType;
private String uploadFileName;
3.在执行方法中,将上传文件复制到服务器
String path = ServletActionContext.getServletContext().getRealPath("/up");
File dest = new File(path, uploadFileName);
FileUtils.copyFile(upload, dest);
4.在对应action中设置input视图,页面可设置<s:filederror/><s:actionerror/>查看错误信息
<result name="input">/error.jsp</result>
5.设置文件上传大小,上传类型等
<constant name="struts.multipart.maxSize" value="20971520"></constant>
<inperceptor-ref name="fileUpload">
<param name="allowedExtensions">bmp,txt</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
多文件上传,action采用数组(或List<File>,List<String>)的形式.复制文件时单个存放:
String path = ServletActionContext.getServletContext().getRealPath("/up");
for(int i=0;i<upload.length;i++){
File dest = new File(path,uploadFileName);
FileUtils.copyFile(upload,dest);
}
Fastjson:
JSONObject.toJSONString();
JSONArray.toJSONString();
处理日期:
在属性上添加@JSONField(format="yyyy-MM-dd")注解
Jackson:
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString();
处理日期:
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
使用插件完成ajax操作:
1.配置文件中<package extends="json-default">
2.将元素压入栈顶.
ActionContext.getContext().getValueStack().set("ps",ps);
3.Action的返回视图<result name="" type="json">
<param name="root">ps</param>
普通ajax操作和插件操作的区别:
在服务器端:普通操作只需要使用json三方工具将对象转换成字符串response发送到客户端
而插件操作将对象压入栈顶,配置 包继承,数据返回格式等.
相比之下,使用三方工具包更方便容易.
注解:
@Namespace("/")
@ParentPackage("struts-default")
@Action(value="名称",results={@Result(name="",type="",location="")})
Hibernate
ORM(Object Relation Mapping):对象关系映射
配置文件:
类名.hbm.xml 映射配置文件. 与类在同一个包下
hibernate.cfg.xml 核心配置文件,项目src下,根据project\etc\hibernate.properties配置
hibernate执行原理:
1.通过Configuration().configure()读取并解析hibernate.cfg.xml配置文件,
在这个配置文件中通过<mapping resource="xxx/xxx/类名.hbm.xml">读取解析
映射信息.
2.config.buildSessionFactory()得到sessionFactory对象
3.sessionFactory.openSession()得到session对象
4.session.beginTransaction()开启事务
5.持久化操作
6.session.getTransaction().commit()提交事务
7.关闭session
8.关闭sessionFactory
总结:通过configuration依次解析读取hibernate.cfg.xml和xxx.hbm.xml配置文件,
然后建立sessionFactory.通过sessionFactory打开session.session开启事务后,
可以执行持久化操作,然后session再关闭事务.最后关闭session,关闭sessionFactory.
hibernate的核心类和接口共有6个,分别为
Configuration,SessionFactory,Session,Transaction,Query,Criteria
1.Configuration
主要加载配置文件
new Configuration().config()加载hibernate.cfg.xml核心配置文件
new Configuration()加载hibernate.properties文件
2.SessionFactory
通过config.buildSessionFactory()得到,属于重量级,通常一个项目一个SessionFactory
SessionFactory通过openSession()/getCurrentSession()得到Session.
可以通过工具类控制SessionFactory唯一:
public class HibernateUtils {
private static Configuration config;
private static SessionFactory sessionFactory;
static{
config=new Configuration().config();
sessionFactory=config.buildSessionFactory();
}
public static Session openSession(){
return sessionFactory.openSession();
}
}
SessionFactory内还维护了一个连接池,要想导入其他连接池,需要配置核心文件
3.Session
可以通过session.beginTransaction()获得Transaction.
用于持久化操作(方法):
save()/saveOrUpdate()
delete()
update()
get/load()
createQuery()
createSQLQuery()
4.Transaction
用于管理事务
commit事务提交
rollback事务回滚
5.Query
查询(两种):HQL语言,本地SQL语句.
分别通过session.createQuery(hql),session.createSQLQuery(sql)获得
查询所有:
Query query=session.createQuery("from Customer");
List<Customer> list=query.list();
分页查询:
query.setFirstResult(10);
query.setMaxResults(10);
查询指定列:
Query query=session.createQuery("select new Customer(name,address) from Customer");
List<Customer> list=query.list();
条件查询:
Query query=session.createQuery("from Customer where name=:myname");
query.setParameter("myname","xxx");
Customer c=(Customer)query.uniqueResult(); // 如果只有一条返回值,可以使用uniqueResult(),否则只能用list()
无名称参数,对?的赋值从0开始
有名称的参数,对名称赋值.
执行本地SQL:
SQLQuery sqlQuery=session.createSQLQuery("select * from t_customer where name=?");
sqlQuery.setParameter(0,"xxx");
sqlQuery.addEntity(Customer.class);// 必须装入实体,进行封装
Customer c=(Customer)sqlQuery.uniqueResult();
hql和sql在查询某列的时候,hql不需要装入实体,而sql需要装入.
Hibernate持久化类与主键生成策略
持久化类Persistent Object(PO)
PO=POJO+hbm映射配置
PO编写规则:
1.无参的public构造方法
2.private属性,并且get/set方法
3.与数据库主键对应的标识属性OID
4.基本数据类型尽量使用包装类
5.PO类不能使用final修饰符
PO类不可以使用final修饰?(hibernate中的get/load方法的区别)
Get/Load方法都是根据id去查询对象.
1.get直接得到持久化类型对象,是立即查询操作.
load得到的是持久化类型的代理对象(子类对象),采用延迟策略查询数据
2.get方法查询结果不存在返回null
load方法查询结果不存在产生ObjectNotFoundException异常
主键生成策略:
主键分为:自然主键(具有业务含义),代理主键(不具有业务含义!!!必用!!!)
代理主键:
identity:mysql
sequence:oracle
native:根据数据库自动选择identity,sequence
uuid:保证生成主键的唯一性(建议采用)
持久化对象的三种状态:
1.瞬时态(临时态,自由态):new出来的对象,不存在OID,与session无关联
2.持久态:具有OID,与session有关联.
3.托管态(游离态,离线态):具有OID,与session无关联
持久化对象会自动更新数据库:(采用快照)
Customer c=session.get(Customer.class,1);
c.setName("tom");
三种状态切换:
new出来的对象是瞬时态,
session的get(),load(),find()等查询出来的对象是持久态
瞬时态通过save(),saveOrUpdate()变为持久态
持久态通过evict(),close(),clear()变为游离态
一级缓存:
session进行save,get,update等进行操作时,就会将持久化对象保存到session中.
下次进行session的load,get,Query的list等方法时就直接从session缓存中获取.
当调用session的close方法时,session缓存清空.
clear()清空一级缓存
evict()清空缓存中指定的对象
refresh()重新查询数据库,用数据库中的信息更新一级缓存与快照
关联映射:
一对一:
唯一外键对应:在任意一方添加外键描述对应关系
主键对应:一方的主键作为另一方的主键
Class Employee{
private Archives archives;
}
Class Archives{
private Employee employee;
}
一对多:
在多的一方添加外键描述对应关系
Class Customer{
private Set<Order> orders;
}
Class Order{
private Customer c;
}
多对多:
通过中间表描述对应关系
Class Student{
Set<Teacher> ts;
}
Class Teacher{
Set<Student> ss;
}
多方(.hbm.xml):
<many-to-one name="一方的对象名" class="一方全类名" column="外键名"></many-to-one>
一方(.hbm.xml):
<set name="对象名">
<key column="外键名"/>
<one-to-many class="多方全类名"/>
</set>
双向关联:
在<many-to-one>,<set>标签中添加cascade="save-update"表示级联添加,cascade="delete"表示级联删除
inverse="true"只能在一方的<set>标签中存在,主要作用是,让多方维护外键.
核心配置文件中:
<mapping resource=""/> 使用/分隔路径
cascade总结:
none:默认值
save-update:底层使用save,update或save-update完成操作
delete:级联删除
delete-ophan:删除与当前对象解除关系的对象.
all:包含save-update,delete操作
all-delete-orphan:包含delete-orphan与all操作.(只能在一方设置)
cascade与inverse有什么区别?
cascade主要完成级联操作
inverse在双向关联情况下,用来指定由哪一方维护外键,true为让对方维护.
注解开发
类上:
@Entity
@Table(name="",catalog="")
主键上:
@id
@GenerateValue 默认native
@GenerateValue(strategy=GenerationType.IDENTITY)
还有sequence等,uuid特殊须自行引入
@GenericGenerator(name="myuuid",strategy="uuid")
@GenerateValue(generator="myuuid")
属性上:(属性不写注解也会生成在表中)
@Column(name="",length="",nullable=true) //name为关键字时,必须使用Column注解
@Temporal(TemporalType.TIMESTAMP)
还有DATE,TIME
@Transient 不生成属性
@Type(type="") 定义类型
一对多配置:
一方:
@OneToMany(targetEntity=Order.class,mappedBy="c",orphanRemoval=true)
//targetEntity相当于<one-to-many class="">.Order.class是多方的类
//mappedBy相当于inverse=true.c是多方持有一方的对象名
//orphanRemoval=true 相当于cascade="delete-orphan"
@Cascade(CascadeType.ALL)!!!推荐使用
多方:
@ManyToOne(targetEntity=Customer.class)
@JoinColumn(name="c_customer_id") //指定生成外键名.
@Cascade(CascadeType.SAVE_UPDATE)
多对多配置(不能做删除操作):
teachers表(放弃维护外键):
@ManyToMany(targetEntity=Student.class,mappedBy="teachers")
//mappedBy="teachers" 另一方持有本方的对象
@Cascade(CascadeType.SAVE_UPDATE)
students表(描述中间表):
@ManyToMany(targetEntity=Teacher.class)
@JoinTable(name="s_t" joinColumns={@joinColumn(name="c_student_id")},inverseJoinColumns={@joinColumn(name="c_teacher_id")})
//joinColumns 本方在中间表的列名
//inverseJoinColumns 对方在中间表的列名
@Cascade(CascadeType.SAVE_UPDATE)
一对一配置
User类:
@OneToOne(targetEntity=IDCard.class,mappedBy="user")
@Cascade(CascadeType.SAVE_UPDATE)
IDCard类:
@OneToOne(targetEntity=User.class)
@JoinColumn(name="c_user_id") //外键
@Cascade(CascadeType.SAVE_UPDATE)
核心配置文件中:
<mapping class=""/> 不是/是.
检索方式(5种):
1.导航图对象检索.(根据已加载的对象导航到其他对象)
Customer c=session.get(Customer.class,2)
c.getOrder().size()
2.OID检索.(get/load )
3.HQL检索.
4.QBC检索.
5.本地SQL检索
HQL检索:
完整句型:
select/update/delete...from...where...group by...having...order by...asc/desc
基本检索:
String hql="from Customer";
List<Customer> list=session.createQuery(hql).list();
排序检索:
String hql="from Order order by money desc";
List<Order> list=session.createQuery(hql).list();
条件检索:
String hql="from Order where money>?";
List<Order> list=session.createQuery(hql).setParameter(0,2000d).list();
String hql="from Order where money>:mymoney";
List<Order> list=session.createQuery(hql).setParameter("mymoney",2000d).list();
分页检索:
Query query=session.createQuery("from Order");
query.setFirstResult((2-1)*6);
query.setMaxResults(6);
List<Order> list=query.list();
分组统计:
String hql="select count(*) from Order";
Object count=session.createQuery(hql).uniqueResult();
String hql="select sum(money) from Order group by c";
List list=session.createQuery(hql).list();
投影检索:
String hql="select name from Customer";
List list=session.createQuery(hql).list();
//必须在PO类中提供对应的构造方法
String hql="select new Customer(id,name) from Customer";
List<Customer> cs=session.createQuery(hql).list();
命名检索:
在Customer.hbm.xml中配置
<query name="myHql">
from Customer
</query>
或在Customer类上添加注解
@NamedQuery(name="myHql",query="from Customer")
使用:
Query query=session.getNamedQuery("myHql");
List<Customer> list=query.list();
Customer c=session.get(Customer.class,1);
Query query=session.getNamedQuery("findOrderByCustomer");
List<Order> list=query.setEntity("c",c).list();
离线条件检索:
DetachedCriteria dc=DetachedCriteria.forClass(Customer.class);
dc.add(Restrictions.like("name","%瑞_");
Session session=HibernateUtils.openSession();
session.beginTransaction();
Criteria criteria=dc.getExecutableCriteria(session);
List<Customer> list=criteria.list();
SQL多表操作
1.交叉连接(cross join)
select * from t_customer cross join t_order;
2.内连接
1)显示(join on)
select * from t_customer c join t_order o on c.id=o.c_customer_id;
2)隐式
select * from t_customer c,t_order o where c.id=o.c_customer_id
3.外连接(outer可以省略)
1)左外连接(left outer join on)
select * from t_customer c left join t_order o on c.id=o.c_customer_id;
2)右外连接(right outer join on)
HQL多表操作
1.内连接
1)显示(join with)
String hql="from Customer c join c.orders with c.id=1";
2)隐式("."运算符关联)
String hql="from Order o where o.c.id=1";
3)迫切内连接(迫切内连接将结果封装到PO类,内连接得到Object[]数组)
****(fetch与distanct连用,fetch不能单独与with连用,限定条件时使用where)
String hql="select distinct c from Customer c join fetch c.orders";
Query query=session.createQuery(hql);
List<Customer> list=query.list();
2.外连接
1)左连接
List<Object[]> list=session.createQuery("from Customer c left join c.orders").list();
2)迫切左外连接
List<Customer> list=session.createQuery("select distinct c from Customer c left outer join fetch c.orders where c.id=1").list();
for(Customer c:list){
syso(c);
}
迫切连接与普通连接的区别:
迫切连接将结果封装到PO类,普通连接将结果装进Object[]数组.
事务管理
事务:事务就是逻辑上的一组操作,组成这组操作的各个单元要么全部成功,要么全都失败.
四大特性:
原子性:不可分割
一致性:执行前后,数据一致
隔离性:不受其他事务干扰
持久性:保存到数据库
隔离性产生的问题:
脏读:读未提交数据
不可重复读:读到update数据
虚读/幻读:读到insert数据
问题解决(Hibernate中隔离级别(1,2,4,8)):
READ_UNCOMMITTED:引发所有隔离问题
READ_COMMITTED:防止脏读 oracle默认级别
REPEATABLE_READ:防止脏读,不可重复读 mysql默认级别
SERIALIZABLE:解决所有问题.(效率最低)
session管理
本地线程绑定session
配置hibernate.cfg.xml:
<property name="hibernate.current_session_context_class">thread</property>
获取session
sessionFactory.getCurrentSession();
注意:这个方法获得的session会自动关闭.不需要手动关闭,否则会报错.
HQL优化:
1.使用参数绑定:既节省CPU时间和内存又避免SQL注入
2.尽量少使用NOT
3.尽量使用where替换having
4.在含有子查询的hql中,尽量减少对表的查询
5.使用表别名
一级缓存优化:
session.evict()
session.clear()
检索策略
1.类级别检索(立即检索和延迟检索,默认是延迟检索true)
1)配置hbm.xml:
<class name="Customer" table="t_customer" lazy="true">
2)在类上使用注解
@Proxy(lazy=true)
对延迟对象进行初始化:
1)对象.get()
2)hibernate.initialize(对象)
****3)openSessionInView filter (Spring框架)
2.关联级别检索
查询到某个对象,获得其关联的对象或属性,这种称为关联级别检索.
c.getOrders().size();
c.getName();
检索策略(fetch和lazy)
一方:Fetch取值:1.SELECT 多条简单的sql (默认值)
2.JOIN 迫切左外连接
3.SUBSELECT 生成子查询的SQL
Lazy取值:1.TRUE 延迟加载 (默认值)
2.FALSE 立即加载
3.EXTRA 加强延迟加载,及其懒惰
注意:采用Fetch采用JOIN时,Lazy失效,程序采用左外连接立即加载
注解:
@Fetch(FetchMode.JOIN)
@LazyCollection(LazyCollectionOpetion.FALSE)
多方:Fetch取值:1.SELECT
2.JOIN
Lazy取值:1.FALSE
2.PROXY 需要另一方的类级别延迟策略来决定
注解:
@Fetch(FetchMode.SELECT)
@LazyToOne(LazyToOneOption.PROXY)
批量抓取
解决N+1问题
注解@BatchSize(size=4)
配置文件在<class>标签上设置 batch-size
注意:无论是根据哪一方来查询另一方,在进行批量抓取时,都是在父方来设置,
如果是要查询子信息,那么我们是在<set>上来设置batch-size,如果是从子方
来查询父方,也是在父方<class>设置batch-size.
|
|