目录
8.1 底层sql实现(复杂的sql hibernate实现不了的时候)
8.3 离线对象criteria和hibernate模板里面方法
1.配置SSH
1.1 导入jar包
网站:
1.2 搭建struts2环境
1)创建action,创建struts.xml配置文件,配置action
2)配置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>
1.3 搭建hibernate环境
1)创建实体类
2)配置实体类和数据库表映射关系
3)创建hibernate核心配置文件 - 引入映射配置文件
<hibernate-configuration>
<session-factory>
<!-- hibernate信息 可选 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- session与本地线程绑定 -->
<!-- <property name="hibernate.current_session_context_class">thread</property> -->
<!-- 将映射文件放到核心配置文件中 -->
<mapping resource="com/entity/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
1.4 搭建spring环境
1)创建spring核心配置文件
2)引入映射配置文件
3)让spring配置文件在服务器启动时候加载(web.xml)
- 配置监听器
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
- 指定spring配置文件位置
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:bean.xml</param-value>
</context-param>
1.5 struts2和spring的整合
1)把action在spring配置(action多实例的)
2)在struts.xml中action标签class属性里面写 bean的id值
1.6 spring和hibernate的整合
1)把hibernate核心配置文件中数据库配置,在spring里面配置
2)把hibernate的sessionFactory在spring配置
<!-- 配置c3p0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 数据库信息 必须-->
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///ssh_crm?useUnicode=true&characterEncoding=UTF-8"></property>
<property name="user" value="root"></property>
<property name="password" value="532077936"></property>
</bean>
<!-- sessionfactory创建 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocations" value="classpath:hibernate.cfg.xml"></property>
</bean>
1.7 互相的注入关系
Action注入Service
Service注入Dao实现类
Dao实现类(继承HibernateDaoSupport)注入HibernateTemplate(注入sessionFactory)
*继承的话就不用在配置文件再写HibernateTemplate的对象(通过注入sessionFactory会设置HibernateTemplate)了
<bean id="userAction" class="com.tencent.action.UserAction" scope="prototype">
<property name="userService" ref="userService"></property>
</bean>
<bean id="userService" class="com.tencent.service.UserService">
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.tencent.dao.UserDaoImpl">
<!-- <property name="hibernateTemplate" ref="hibernateTemplate"></property> -->
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
1.8 bean.xml中配置事务
<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 开启注解 指定事务管理器 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
1.9 property属性中value和ref的不同
>>>ref指向的是一个bean的id
>>>value=一个java类
2.分页管理
2.1 PageBean实体类
//当前页
private Integer currentPage;
//总记录数
private Integer totalCount;
//总页数
private Integer totalPage;
//一页几条记录
private Integer pageSize;
//开始位置
private Integer begin;
//每页记录的集合
private List<Customer> list;
//......get/set方法.......//
2.2 -->页面
从页面中获取currentPage值,
点击列表时(传currentPage=1),点击下一页(currentPage+=1),点击上一页(currentPage-=1)
2.3 -->Action
public String pagelist() {
PageBean pagebean = customerService.listpage(currentPage);
ServletActionContext.getRequest().setAttribute("pageBean", pagebean);
return "pagelist";
}
2.4 -->Service(封装PageBean对象)
public PageBean listpage(Integer currentPage) {
PageBean pageBean = new PageBean();
//设置当前页
pageBean.setCurrentPage(currentPage.intValue());
//设置总记录数
int totalCount = customerDao.findCount();
pageBean.setTotalCount(totalCount);
//设置一页最多要显示的记录数
int pageSize = 5;
//设置总页数
int totalPage = 0;
if(totalCount % pageSize == 0) {
totalPage = totalCount/pageSize;
}else {
totalPage = totalCount/pageSize+1;
}
pageBean.setTotalPage(totalPage);
//设置开始位置,从第几条记录开始查询
int begin = (currentPage-1)*pageSize;
List<Customer> list = customerDao.findPage(begin,pageSize);
pageBean.setList(list);
return pageBean;
}
2.5 -->Dao(两种方式)
public List<Customer> findPage(int begin, int pageSize) {
/*
* 第一种方法 使用hibernate底层代码实现
*/
// SessionFactory sessionFactory = this.getHibernateTemplate().getSessionFactory();
// Session session = sessionFactory.getCurrentSession();
// Query query = session.createQuery("from Customer");
// query.setFirstResult(begin);
// query.setMaxResults(pageSize);
// List<Customer> list = query.list();
/*
* 第二种 使用离线对象和hibernateTemplate的方法实现
*/
DetachedCriteria criteria = DetachedCriteria.forClass(Customer.class);
List<Customer> list =
(List<Customer>)this.getHibernateTemplate().findByCriteria(criteria, begin, pageSize);
return list;
}
3.文件上传到服务器
3.0 原理
Struts2使用拦截器对FileUpload进行了封装
3.1上传表单页面的要求
①表单提交方式post
②form标签里面有属性enctype,值为multipart/form-data
③表单里面有上传项<input type="file" name="upload"/> name要同Action里面的File对象同名
3.2 Action得到上传文件名称和上传文件
①定义两个变量(属性封装),分别代表文件以及文件名,文件名命名要同File名一样(upload) 再加 FileName
private File upload;
private String uploadFileName;
public File getUpload() {
return upload;
}
public void setUpload(File upload) {
this.upload = upload;
}
public String getUploadFileName() {
return uploadFileName;
}
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName;
}
3.3 在Action的方法中上传服务器
①在服务器里面创建文件
②把上传得到的文件复制到服务器文件里面
if(upload != null) {
//在服务器文件夹里面创建文件
File serverFile = new File("D:\\sshtest"+"/"+uploadFileName);
//把上传的文件复制到服务器文件中
FileUtils.copyFile(upload, serverFile);
}
3.4 文件大小限制以及input结果定义
文件上传大小超出限制&input输出未定义:
①默认限制大小2M,可以在struts.xml里面配置常量struts.multipart.maxSize=最大字节数
②超过限制的话,自动返回结果,即return "input"
所以可以配置<result name="input"> .... </result>在出错时到所需的页面
在input转发到的页面中可以用标签Struts的标签<s:actionerror/> 看到具体错误
4.级联查询NO SESSION
4.0 情景
eg:关系:联系人(多) 对 (一)用户
现需要查询联系人下的用户的名称
如果传入的是list中的linkMan
以linkMan.customer.custName来获取值就会报No Session
4.1 原因
用的是hibernate框架,主要靠的是session来进行对数据的crud
而hibernate默认在Dao层操作完之后就关闭session
在action中发现有需要linkMan关联的customer的属性(除作为外键的主键cid)就需要重返dao层查询数据
而此时已经没有session了,所以报错了
4.2 解决
- 让session操作之后不会马上关闭,在action操作之后进行关闭
- 封装实现方式:让session延迟关闭
封装过滤器,只需要配置封装的过滤器就可以了
配置到struts2过滤器前面 (不是覆盖 而是之后的不执行?)
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
5.级联删除
5.0 情景
eg:关系:联系人(多) 对 (一)用户
要删除用户,需求有两种:
①把用户对应的多个联系人都删了
②用户的外键设置为NULL
5.1 原理
hibernate的外键双向维护
封装的属性
5.2 实现
需求①:在用户的配置文件中的联系人 设置<set name="linkMan" inverse="true" cascade="delete">...</set>
表示(一)用户放弃了外键维护,并启动了级联删除
需求②:inverse和cascade都不配置,默认效果
ps:如果只设置了inverse=true 会出现异常
6.多对多的实现
6.0 核心思想
多对多 的 拆分 两个 一对多
6.1 情景
两个表 User、Customer
需求是,一个User可以Visit多个Customer,一个Customer可以被多个User Visit
6.2 具体实现
①直接使用多对多建立关系(不建议使用)
直接用外键互相关联两个表的主键
具体实现事例可看https://blog.csdn.net/TypantK/article/details/82974956
②拆分成两个一对多,建立多一个实体类来建立关系
将(User)多对多(Customer)转换成 (User)一 对 (Visit)多(Visit) 对 一(Customer)
具体逻辑:一个User可以有多个Visit记录,一个Customer可以有多个被Visit记录,一个Visit记录只能有一个User和一个Customer
6.3 图分析
6.4 ①②比较的优点
①方式可以减少一张表
②方式可以多几个表字段,比如Visit记录下,Visit的内容,Visit的时间,Visit的地址等
7.抽取BaseDao
对重复的代码(只是参数上传的类型不同)方法等,进行抽取,通过泛型来简化代码
得到类Class方式
>> Class.forName(...)
>> 类名.class
>> 对象.getClass() ;
this.getClass() ;
>> getClass方法是Object类的方法
对于需要获取类型的class的方法(没有T.class这种写法),通过反射来获得类型名称
public BaseDaoImpl() {
//1 获取当前运行对象的class
//比如运行customerDao实现类,得到customerDao实现类class
Class clazz = this.getClass();
//2 获取运行类的父类的参数化类型
Type type = clazz.getGenericSuperclass();
//3 转换成子接口ParameterizedType
ParameterizedType ptype = (ParameterizedType) type;
//4 获取实际类型参数
//比如 Map<key,value>
Type[] types = ptype.getActualTypeArguments();
//5 把Type变成class
Class clazzParameter = (Class) types[0];
this.clazzType = clazzParameter;
}
8.多条件组合查询
8.1 底层sql实现(复杂的sql hibernate实现不了的时候)
1)得到sessionFactory对象,得到session对象
2)调用session里面的方法创建SQLQuery对象
3)返回结果的结果转换
使用sqlQuery.list()返回的list中都是数组的形式
可以通过此方法转换成MAP形式,如果只有两个字段
8.2 hibernate模板里面的find方法实现
//使用hibernate模板里面find方法实现
//拼接hql语句
String hql = "from Customer where 1=1 ";
//创建list集合,如果值不为空,把值设置到list里面
List<Object> p = new ArrayList<Object>();
//判断条件值是否为空,如果不为空拼接hql语句
if(customer.getCustName()!=null && !"".equals(customer.getCustName())) {
//拼接hql
hql += " and custName=?";
//把值设置到list里面
p.add(customer.getCustName());
}
if(customer.getCustLevel()!=null && !"".equals(customer.getCustLevel())) {
hql += " and custLevel=?";
p.add(customer.getCustLevel());
}
return (List<Customer>) this.getHibernateTemplate().find(hql, p.toArray());
8.3 离线对象criteria和hibernate模板里面方法
//1 创建离线对象,指定对哪个实体类进行操作
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
//2 判断条件值是否为空,设置值
if(customer.getCustName()!=null && !"".equals(customer.getCustName())) {
//调用方法实现
//调用add方法,表示设置条件值
//add方法里面使用Restrictions类里面静态的方法实现
detachedCriteria.add(Restrictions.eq("custName", customer.getCustName()));
}
if(customer.getCustLevel()!=null && !"".equals(customer.getCustLevel())) {
detachedCriteria.add(Restrictions.eq("custLevel", customer.getCustLevel()));
}
//3执行离线对象
//调用hibernate模板里面的方法实现
List<Customer> list =
(List<Customer>) this.getHibernateTemplate().findByCriteria(detachedCriteria);
return list;
9.数据字典表(码表)
9.0 什么是数据字典表(码表)
存储一些基本的数据,可以通过主键来查询更详细的信息
比如客户的级别,1 代表 普通用户、2 代表 会员、3 代表 管理员 等 这种
数据字典表(级别表)【一】 对 【多】 用到数据字典表的表(用户表)
9.1 数据字典表的实体类创建以及配置
创建就同一般的实体类一样,
一个id作为主键,
另一个作为更详细信息的数据(比如String dname,存储普通用户、会员等)
**配置方面在需要用到数据字典表的表(用户表)的配置文件中要配置 数据字典表的信息
<many-to-one name="dictUserLevel" class="cn.entity.dist" >
**而数据字典表中不用配置 需要用到数据字典表(用户表)的信息
不用配置<one-to-many ...../>