PageBean.javajavascript
package com.itheima.crm.page;
import java.util.List;
public class PageBean<T> {
/*
算法1:
if(totalRecord % pageSize == 0) {
totalPage = totalRecord / pageSize;
} else { // 半页
totalPage = totalRecord / pageSize + 1;
}
算法2:
totalPage = (totalRecord + (pageSize - 1)) / pageSize;
*/
// 必须项
private int pageNum; // 第几页(当前页)
private int pageSize; // 每页显示个数(固定值)
private int totalRecord; // 总记录数(查询数据库)
// 计算项
private int startIndex; // 开始索引(计算)
private int totalPage; // 总分页数(计算)
// 分页数据
private List<T> data; // 传过来什么就是什么
// 含参构造(含有3个参数的构造方法,这样就能告诉使用者须要这三个必选项)
public PageBean(int pageNum, int pageSize, int totalRecord) {
super();
this.pageNum = pageNum;
this.pageSize = pageSize;
this.totalRecord = totalRecord;
// 计算项
// 一、开始索引(索引从0开始)
this.startIndex = (this.pageNum -1) * this.pageSize;
// 二、总分页数
this.totalPage = (this.totalRecord + (this.pageSize - 1)) / this.pageSize;
}
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalRecord() {
return totalRecord;
}
public void setTotalRecord(int totalRecord) {
this.totalRecord = totalRecord;
}
public int getStartIndex() {
return startIndex;
}
public void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public List<T> getData() {
return data;
}
public void setData(List<T> data) {
this.data = data;
}
}
package com.itheima.crm.page;
import java.sql.SQLException;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
public class PageHibernateCallback<T> implements HibernateCallback<List<T>> {
private String hql;
private Object[] params;
private int startIndex;
private int pageSize;
// 上面的4个参数如何传入进来呢?
// 方式一:增长4个setter方法,使用时new出这个类,而后调用4个setter方法,一个一个set进去便可
// 方式二:经过含参构造方法,使用时new出这个类,同时传入4个参数
// 方式三:非传统的set方法,即链式编程。步骤以下:
// 5.一、首先,只要setter方法,不要getter方法
// 5.二、返回值类型是本身,返回的是本身
// 5.三、使用时,先new出对象,再setXxx().setXxx().setXxx()...
public PageHibernateCallback<T> setHql(String hql) {
this.hql = hql;
return this;
}
public PageHibernateCallback<T> setParams(Object[] params) {
this.params = params;
return this;
}
public PageHibernateCallback<T> setStartIndex(int startIndex) {
this.startIndex = startIndex;
return this;
}
public PageHibernateCallback<T> setPageSize(int pageSize) {
this.pageSize = pageSize;
return this;
}
@Override
public List<T> doInHibernate(Session session) throws HibernateException, SQLException {
// 一、经过HQL语句,得到Query对象
Query queryObject = session.createQuery(hql);
// 二、条件设置
for (int i = 0; i < params.length; i++) {
queryObject.setParameter(i, params[i]);
}
// 三、分页
queryObject.setFirstResult(startIndex);
queryObject.setMaxResults(pageSize);
// 四、查询全部
return queryObject.list();
}
}
CourseTypeDao.javaphp
/**
* 分页,查询总记录数
*
* @param condition
* @param params
* @return
*/
public int getTotalRecord(String condition, Object[] params);
/**
* 分页,查询结果
*
* @param condition 条件
* @param params 条件的实际参数
* @param startIndex 开始索引
* @param pageSize 每页显示的个数
* @return
*/
public List<CrmCourseType> findAll(String condition, Object[] params, int startIndex, int pageSize);
CourseTypeDaoImpl.javacss
@Override
public int getTotalRecord(String condition, Object[] params) {
String hql = "select count(c) from CrmCourseType c where 1=1 " + condition;
List<Long> list = this.getHibernateTemplate().find(hql, params); // 聚合函数查询
return list.get(0).intValue(); // 包装类就是点方法,基本类就是强转
}
@Override
public List<CrmCourseType> findAll(String condition, Object[] params, int startIndex, int pageSize) {
String hql = "from CrmCourseType where 1=1 " + condition;
// HQL不支持分页,QBC支持分页,因此若是使用HQL,须要咱们自定义实现类
return this.getHibernateTemplate().execute(new PageHibernateCallback<CrmCourseType>().setHql(hql).setParams(params).setStartIndex(startIndex).setPageSize(pageSize));
}
CourseTypeService.javahtml
/**
* 带有条件的查询全部课程类别 + 分页
*
* @param courseType 条件
* @param pageNum 第几页(当前页)
* @param pageSize 每页显示个数
* @return
*/
public PageBean<CrmCourseType> findAllCourseType(CrmCourseType courseType, int pageNum, int pageSize);
CourseTypeServiceImpl.javajava
@Override
public PageBean<CrmCourseType> findAllCourseType(CrmCourseType courseType, int pageNum, int pageSize) {
// 1.一、使用StringBuilder 接收:拼凑查询条件
StringBuilder builder = new StringBuilder();
// 1.二、使用List 接收:拼凑实际参数,须要能够重复,有顺序 => 选择 List集合
List<Object> paramsList = new ArrayList<Object>();
// 二、过滤条件
// 2.一、过滤课程类别,不须要 null 或者 "" 或者 " ",使用工具类
if (StringUtils.isNotBlank(courseType.getCourseName())) {
builder.append(" and courseName like ?");
paramsList.add("%" + courseType.getCourseName() + "%");
}
// 2.二、过滤课程简介,不须要 null 或者 "" 或者 " ",使用工具类
if (StringUtils.isNotBlank(courseType.getRemark())) {
builder.append(" and remark like ?");
paramsList.add("%" + courseType.getRemark() + "%");
}
// 2.三、过滤总学时
if (StringUtils.isNotBlank(courseType.getTotalStart())) {
builder.append(" and total >= ?");
paramsList.add(Integer.parseInt(courseType.getTotalStart()));
}
if (StringUtils.isNotBlank(courseType.getTotalEnd())) {
builder.append(" and total <= ?");
paramsList.add(Integer.parseInt(courseType.getTotalEnd()));
}
// 2.三、过滤总费用
if (StringUtils.isNotBlank(courseType.getCourseCostStart())) {
builder.append(" and courseCost >= ?");
paramsList.add(Double.parseDouble(courseType.getCourseCostStart()));
}
if (StringUtils.isNotBlank(courseType.getCourseCostEnd())) {
builder.append(" and courseCost <= ?");
paramsList.add(Double.parseDouble(courseType.getCourseCostEnd()));
}
// 三、使用数据
// 一、条件,格式:“and ...? and ...?”
String condition = builder.toString();
// 二、实际参数
Object[] params = paramsList.toArray();
// 二、分页
// 2.一、总记录数 totalRecord
int totalRecord = this.courseTypeDao.getTotalRecord(condition, params);
// 2.二、建立PageBean对象
PageBean<CrmCourseType> pageBean = new PageBean<CrmCourseType>(pageNum, pageSize, totalRecord);
// 2.三、分页数据
List<CrmCourseType> data = this.courseTypeDao.findAll(condition, params, pageBean.getStartIndex(), pageBean.getPageSize());
pageBean.setData(data);
return pageBean;
}
/day36_06_Spring_crm/WebRoot/WEB-INF/pages/coursetype/listCourse.jspweb
......
<%--条件查询 start --%>
<s:form namespace="/" action="courseTypeAction_findAll">
<%-- 提供隐藏域,存放的是须要的当前页 ,id是给js/css使用的,name是给提交表单用的 --%>
<s:hidden id="pageNum" name="pageNum" value="1"></s:hidden>
......
<td align="right">
<span>第<s:property value="#pageBean.pageNum"/>/<s:property value="#pageBean.totalPage"/>页</span>
<span>
<s:if test="#pageBean.pageNum gt 1"><%--gt 等价于 < --%>
<a href="javascript:void(0)" onclick="showPage(1)">[首页]</a> <%-- 首页 = 1 --%>
<a href="javascript:void(0)" onclick="showPage(<s:property value="#pageBean.pageNum - 1"/>)">[上一页]</a> <%-- 上一页 = 当前页 - 1 --%>
</s:if>
<s:if test="#pageBean.pageNum lt #pageBean.totalPage"><%--lt 等价于 > --%>
<a href="javascript:void(0)" onclick="showPage(<s:property value="#pageBean.pageNum + 1"/>)">[下一页]</a> <%-- 下一页 = 当前页 + 1 --%>
<a href="javascript:void(0)" onclick="showPage(<s:property value="#pageBean.totalPage"/>)">[尾页]</a> <%-- 尾页 --%>
</s:if>
</span>
</td>
</tr>
</table>
<script type="text/javascript">
function showPage(num) {
// 一、修改隐藏域的值
document.getElementById("pageNum").value = num;
// 二、提交表单
document.forms[0].submit();
}
</script>
......
PageBean.java算法
......
// 增长动态显示条
private int start;
private int end;
// 含参构造(含有3个参数的构造方法,这样就能告诉使用者须要这三个必选项)
public PageBean(int pageNum, int pageSize, int totalRecord) {
super();
this.pageNum = pageNum;
this.pageSize = pageSize;
this.totalRecord = totalRecord;
// 计算项
// 一、开始索引(索引从0开始)
this.startIndex = (this.pageNum -1) * this.pageSize;
// 二、总分页数
this.totalPage = (this.totalRecord + (this.pageSize - 1)) / this.pageSize;
// 三、增长动态显示条
// 3.一、初始化数据,暂定显示10个分页
this.start = 1; // 开始的分页
this.end = 10; // 最后的分页
// 3.二、处理数据,假如:总分页数 totalPage = 4
if (this.totalPage <= 10) {
this.end = this.totalPage; // 最后的分页=总分页数
} else {
// 假如:总分页数 totalPage = 15
// 3.三、当前页:前4后5
this.start = this.pageNum - 4;
this.end = this.pageNum + 5;
if (this.start < 1) {
this.start = 1;
this.end = 10;
}
if (this.end > this.totalPage) {
this.start = this.totalPage - 9;
this.end = this.totalPage;
}
}
......
listCourse.jspspring
......
<s:if test="#pageBean.pageNum gt 1"><%--gt 等价于 < --%>
<a href="javascript:void(0)" onclick="showPage(1)">[首页]</a> <%-- 首页 = 1 --%>
<a href="javascript:void(0)" onclick="showPage(<s:property value="#pageBean.pageNum - 1"/>)">[上一页]</a> <%-- 上一页 = 当前页 - 1 --%>
</s:if>
<%-- 添加动态显示条 --%>
<s:iterator begin="#pageBean.start" end="#pageBean.end" var="num">
<a href="javascript:void(0)" onclick="showPage(<s:property value="#num"/>)"><s:property value="#num"/></a>
</s:iterator>
<s:if test="#pageBean.pageNum lt #pageBean.totalPage"><%--lt 等价于 > --%>
<a href="javascript:void(0)" onclick="showPage(<s:property value="#pageBean.pageNum + 1"/>)">[下一页]</a> <%-- 下一页 = 当前页 + 1 --%>
<a href="javascript:void(0)" onclick="showPage(<s:property value="#pageBean.totalPage"/>)">[尾页]</a> <%-- 尾页 --%>
</s:if>
......
package com.itheima.testthis;
public class Parent {
public void init() {
System.out.println("1 parent init");
this.demo();
}
public void demo() {
System.out.println("2 parent demo");
}
}
Son.javasql
package com.itheima.testthis;
public class Son extends Parent {
public void init() {
super.init();
System.out.println("3 son init");
this.demo();
}
public void demo() {
System.out.println("4 son demo");
}
}
TestThis.java数据库
package com.itheima.testthis;
public class TestThis {
public static void main(String[] args) {
// Parent parent = new Parent();
// parent.init();
// this在编译时指的是当前类,在运行时指的是当前运行类,对字段和方法的处理方式是不同的。
Son son = new Son();
son.init();
}
}
测试结果
1 parent init
4 son demo
3 son init
4 son demo
之前的作法:
1. 将Dao层通用的方法进行统一实现。
2. 以后在dao层使用dao接口,即StaffDao。
3. StaffDao接口,须要继承 BaseDao接口,从而对外能够提供多个方法,便可以直接使用BaseDao的方法 + 本身特有的方法。
4. BaseDaoImpl实现类,须要继承 HibernateDaoSupport,从而能够调用HibernateTemplate,至关于以前直接编写dao实现类。同时须要实现BaseDao接口,从而将公共内容都完成。
5. StaffDaoImpl实现类,须要继承 BaseDaoImpl实现类,从而全部的公共内容均可以使用了。同时须要实现StaffDao接口,从而完成特有的功能。
示例代码以下:
BaseDao.java
package com.itheima.crm.base;
import java.util.List;
public interface BaseDao<T> {
public void save(T t);
public void update(T t);
public void delete(T t);
public void saveOrUpdate(T t);
public T findById(java.io.Serializable id);
public List<T> findAll();
// ......
}
BaseDaoImpl.java
package com.itheima.crm.base.impl;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.itheima.crm.base.BaseDao;
public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> {
// 定义变量接收实际参数
private Class<?> beanClass;
// T 在编译时,只是变量,在运行是才能够得到具体的类型
public BaseDaoImpl() {
// 经过构造方法去得到运行时的类型,BaseDaoImpl<CrmStaff> 叫作被参数化的类型
ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
// 得到实际参数值,如下方法得到的是全部的实际参数值,可是咱们此时只有一个
beanClass = (Class<?>) parameterizedType.getActualTypeArguments()[0];
}
@Override
public void save(T t) {
this.getHibernateTemplate().save(t);
}
@Override
public void update(T t) {
this.getHibernateTemplate().update(t);
}
@Override
public void delete(T t) {
this.getHibernateTemplate().delete(t);
}
@Override
public void saveOrUpdate(T t) {
this.getHibernateTemplate().saveOrUpdate(t);
}
@Override
public T findById(Serializable id) {
return (T) this.getHibernateTemplate().get(beanClass, id);
}
@Override
public List<T> findAll() {
// beanClass.getName() 得到的是类的全限定名称 例如:com.itheima.crm.staff.domain.CrmStaff
return this.getHibernateTemplate().find("from " + beanClass.getName());
}
// 回顾hql语句
// session.createQuery("from CrmStaff"); // 简便写法,存在自动导包
// session.createQuery("from com.itheima.crm.staff.domain.CrmStaff"); // 完整写法
}
以Staff进行举例:
StaffDao.java
package com.itheima.crm.staff.dao;
import com.itheima.crm.base.BaseDao;
import com.itheima.crm.staff.domain.CrmStaff;
public interface StaffDao extends BaseDao<CrmStaff> {
/**
* 经过用户名和密码查询员工
*
* @param loginName
* @param loginPwd
* @return
*/
public CrmStaff find(String loginName, String loginPwd);
}
StaffDaoImpl.java
package com.itheima.crm.staff.dao.impl;
import java.util.List;
import com.itheima.crm.base.impl.BaseDaoImpl;
import com.itheima.crm.staff.dao.StaffDao;
import com.itheima.crm.staff.domain.CrmStaff;
@SuppressWarnings("unchecked")
public class StaffDaoImpl extends BaseDaoImpl<CrmStaff> implements StaffDao {
@Override
public CrmStaff find(String loginName, String loginPwd) {
List<CrmStaff> allStaff = this.getHibernateTemplate().find("from CrmStaff where loginName=? and loginPwd=?", loginName, loginPwd);
if (allStaff.size() == 1) {
return allStaff.get(0);
}
return null;
}
}
主要思想:
一、封装数据
二、让Spring一会儿注入多个service
三、分页的数据
四、简化值栈操做
BaseAction.java
package com.itheima.crm.base;
import java.lang.reflect.ParameterizedType;
import com.itheima.crm.coursetype.service.CourseTypeService;
import com.itheima.crm.department.service.DepartmentService;
import com.itheima.crm.post.service.PostService;
import com.itheima.crm.staff.service.StaffService;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class BaseAction<T> extends ActionSupport implements ModelDriven<T> {
// 一、封装数据
private T t;
@Override
public T getModel() {
return t;
}
// 1.一、实例化T,能够经过反射去new出T
public BaseAction() {
try {
// 一、要先得到该类运行时的Class
ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
Class<T> clazz = (Class<T>) parameterizedType.getActualTypeArguments()[0];
// 二、经过反射去建立实例
t = clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException(e); // 把编译时异常转换成运行时异常
}
}
// 二、让Spring一会儿注入多个service
// 提供setter方法,是让Spring进行注入的
// 提供getter方法,是让子类能够得到Spring注入的对象的
// 2.一、员工的service
private StaffService staffService;
public void setStaffService(StaffService staffService) {
this.staffService = staffService;
}
public StaffService getStaffService() {
return staffService;
}
// 2.二、职务的service
private PostService postService;
public void setPostService(PostService postService) {
this.postService = postService;
}
public PostService getPostService() {
return postService;
}
// 2.三、部门的service
private DepartmentService departmentService;
public void setDepartmentService(DepartmentService departmentService) {
this.departmentService = departmentService;
}
public DepartmentService getDepartmentService() {
return departmentService;
}
// 2.四、课程类别的service
private CourseTypeService courseTypeService;
public void setCourseTypeService(CourseTypeService courseTypeService) {
this.courseTypeService = courseTypeService;
}
public CourseTypeService getCourseTypeService() {
return courseTypeService;
}
// 2.五、班级的service
// 三、分页的数据
// 第几页(当前页)
private int pageNum = 1;
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getPageNum() {
return pageNum;
}
// 每页显示个数(固定值)
private int pageSize = 2; // 固定值,不用提供setter方法
public void setPageSize(int pageSize) { // 若是写了setter方法,为了之后扩展留下接口
this.pageSize = pageSize;
}
public int getPageSize() {
return pageSize;
}
// 四、简化值栈操做
public void push(Object o) {
ActionContext.getContext().getValueStack().push(o);
}
public void set(String key, Object o) {
ActionContext.getContext().getValueStack().set(key, o);
}
public void put(String key, Object value) {
ActionContext.getContext().put(key, value);
}
public void putSession(String key, Object value) {
ActionContext.getContext().getSession().put(key, value);
}
public void putApplication(String key, Object value) {
ActionContext.getContext().getApplication().put(key, value);
}
}
思路:
1. ClassesDao / ClassesDaoImpl --> 继承BaseDao / BaseDaoImpl
2. service
3. spring配置,完善BaseAction
4. ClassesAction --> 继承BaseAction
5. left.jsp --> struts.xml/struts-classes.xml --> listClass.jsp
一、
ClassesDao.java
package com.itheima.crm.classes.dao;
import com.itheima.crm.base.BaseDao;
import com.itheima.crm.classes.domain.CrmClasses;
public interface ClassesDao extends BaseDao<CrmClasses> {
}
ClassesDaoImpl.java
package com.itheima.crm.classes.dao.impl;
import com.itheima.crm.base.impl.BaseDaoImpl;
import com.itheima.crm.classes.dao.ClassesDao;
import com.itheima.crm.classes.domain.CrmClasses;
public class ClassesDaoImpl extends BaseDaoImpl<CrmClasses> implements ClassesDao {
}
二、
ClassesService.java
package com.itheima.crm.classes.service;
import java.util.List;
import com.itheima.crm.classes.domain.CrmClasses;
public interface ClassesService {
/**
* 查询全部班级
*
* @return
*/
public List<CrmClasses> findAll();
}
ClassesServiceImpl.java
package com.itheima.crm.classes.service.impl;
import java.util.List;
import com.itheima.crm.classes.dao.ClassesDao;
import com.itheima.crm.classes.domain.CrmClasses;
import com.itheima.crm.classes.service.ClassesService;
public class ClassesServiceImpl implements ClassesService {
private ClassesDao classesDao;
public void setClassesDao(ClassesDao classesDao) {
this.classesDao = classesDao;
}
@Override
public List<CrmClasses> findAll() {
return this.classesDao.findAll();
}
}
三、
applicationContext.xml
<!-- 4.五、班级 -->
<import resource="applicationContext-classess.xml"/>
applicationContext-classess.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 班级配置项 dao、service-->
<bean id="classesDao" class="com.itheima.crm.classes.dao.impl.ClassesDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="classesService" class="com.itheima.crm.classes.service.impl.ClassesServiceImpl">
<property name="classesDao" ref="classesDao"></property>
</bean>
</beans>
BaseAction.java
......
// 2.五、班级的service
private ClassesService classesService;
public void setClassesService(ClassesService classesService) {
this.classesService = classesService;
}
......
四、
ClassesAction.java
package com.itheima.crm.classes.web.action;
import java.util.List;
import com.itheima.crm.base.BaseAction;
import com.itheima.crm.classes.domain.CrmClasses;
public class ClassesAction extends BaseAction<CrmClasses> {
public String findAll() {
List<CrmClasses> allClasses = this.getClassesService().findAllClasses();
this.set("allClasses", allClasses);
return "findAll";
}
}
五、
/day36_06_Spring_crm/WebRoot/WEB-INF/pages/frame/left.jsp
d.add('010301','0103','班级管理','${pageContext.request.contextPath}/classesAction_findAll','','right');
struts.xml
<!-- 3.四、班级-->
<include file="struts/struts-classes.xml"></include>
struts-classes.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="cla" namespace="/" extends="common">
<action name="classesAction_*" class="com.itheima.crm.classes.web.action.ClassesAction" method="{1}">
<!-- 一、查询全部班级 -->
<result name="findAll">/WEB-INF/pages/classes/listClass.jsp</result>
</action>
</package>
</struts>
/day36_06_Spring_crm/WebRoot/WEB-INF/pages/classes/listClass.jsp
......
<s:iterator value="allClasses" status="vs">
<tr class="<s:property value="#vs.even ? 'tabtd2' : 'tabtd1'"/>">
<td align="center"><s:property value="name"/></td>
<td align="center"><s:property value="courseType.courseName"/></td>
<td align="center"><s:date name="beginTime" format="yyyy-MM--dd"/></td>
<td align="center"><s:date name="endTime" format="yyyy-MM--dd"/></td>
<td align="center"><s:property value="status"/></td>
<td align="center"><s:property value="totalCount"/></td>
<td align="center"><s:property value="upgradeCount"/></td>
<td align="center"><s:property value="changeCount"/></td>
<td align="center">
<a href="${pageContext.request.contextPath}/pages/classesm/addOrEditClass.jsp">
<img src="${pageContext.request.contextPath}/images/button/modify.gif" class="img"/></a>
</td>
<td align="center">
<a href="${pageContext.request.contextPath}/pages/classesm/showClass.jsp">
<img src="${pageContext.request.contextPath}/images/button/modify.gif" class="img"/></a>
</td>
<td align="center" title="上次上传时间:2015-04-02">
<a href="${pageContext.request.contextPath}/pages/classesm/uploadClass.jsp">上传</a>
<a href="${pageContext.request.contextPath}/pages/classesm/downloadClass">下载</a> <br/>
</td>
</tr>
</s:iterator>
......
ClassesService.java
/**
* 经过班级id查询班级详情
*
* @return
*/
public CrmClasses findById(String classesId);
ClassesServiceImpl.java
@Override
public CrmClasses findById(String classesId) {
return this.classesDao.findById(classesId);
}
ClassesAction.java
public String uploadUI() {
CrmClasses findClasses = this.getClassesService().findById(this.getModel().getClassesId());
// 将查询到的数据压入栈顶(为了更方便的回显数据)
this.push(findClasses);
return "uploadUI";
}
struts-classes.xml
<!-- 二、显示上传表单页面 -->
<result name="uploadUI">/WEB-INF/pages/classes/uploadClass.jsp</result>
listClass.jsp
<s:a namespace="/" action="classesAction_uploadUI">
<s:param name="classesId" value="classesId"></s:param> <%--由于上传文件以前须要经过id查询班级详情 --%>
上传
</s:a>
uploadClass.jsp
......
<table width="88%" border="0" class="emp_table" style="width:80%;">
<tr>
<td width="120">课程类别:</td>
<td><s:property value="courseType.courseName"/></td>
<td> </td>
</tr>
<tr>
<td>班级:</td>
<td><s:property value="name"/></td>
<td> </td>
</tr>
<tr>
<td>上次上传时间:</td>
<td><s:date name="uploadTime"/></td>
<td> </td>
</tr>
<tr>
<td>选择课表:</td>
<td> </td>
<td> </td>
</tr>
<tr>
<td colspan="3">
<input type="file" name="schedule" value="" />
</td>
</tr>
</table>
......
0. 先经过班级id查询班级详情,如上
1. 替换表单
<form action="/crm2/classesm/classAction_upload.action" method="post" enctype="multipart/form-data">
<input type="file" name="schedule">
2. 编写action类,struts已经把文件上传功能都完成了,咱们只须要把须要的东西拿来就能够了。
咱们须要但愿struts把内容注入给咱们,则就在action类中提供须要的字段,再提供setter方法便可。
private File schedule; // 文件内容
private String scheduleFileName; // 文件名称
private String scheduleContentType; // 文件类型
3. 将课表保存到硬盘,将课表的文件路径、文件名称、更新时间,更新到数据库。
4. struts中拦截器的设置,由于咱们上传的是课表。设置容许上传的文件类型。
5. 文件上传不成功。ClassesAction类中使用注解@InputConfig 开发,struts-classes.xml中添加相应的配置。
/**
* 文件(课表)上传
*
* @return
* @throws IOException
*/
@InputConfig(resultName="uploadInput")
public String upload() throws IOException {
6. 文件上传不成功时的错误信息的国际化显示。
一、
uploadClass.jsp
......
<s:form namespace="/" action="classAction_upload.action" enctype="multipart/form-data">
......
<s:file name="schedule"></s:file>
......
二、
ClassesAction.java
private File schedule; // 文件内容
private String scheduleFileName; // 文件名称
private String scheduleContentType; // 文件类型
public void setSchedule(File schedule) {
this.schedule = schedule;
}
public void setScheduleFileName(String scheduleFileName) {
this.scheduleFileName = scheduleFileName;
}
public void setScheduleContentType(String scheduleContentType) {
this.scheduleContentType = scheduleContentType;
}
/**
* 文件(课表)上传
*
* @return
* @throws IOException
*/
@InputConfig(resultName="uploadInput")
public String upload() throws IOException {
// 一、将课表保存在硬盘(企业级开发中,图片会上传到图片服务器,图片服务器返回一个路径,咱们把该路径保存在数据库中便可)
// 1.一、在tomcat下,位置在.../WEB-INF/upload/...
// 方式一:写死父目录,很差
// String parentDir = "D:\learn\JavaWeb\apache-tomcat\apache-tomcat-9.0.7\webapps\day36_06_Spring_crm\WEB-INF\...";
// 方式二:文件父目录
String parentDir = ServletActionContext.getServletContext().getRealPath("/WEB-INF/upload");
// 1.二、咱们但愿文件名是一个32位的随机数,且没有扩展名,这样安全性更高
String fileName = MyStringUtils.getUUID();
// 1.三、保存操做
FileUtils.copyFile(schedule, new File(parentDir, fileName));
// 二、更新操做
this.getModel().setUploadPath("/WEB-INF/upload" + fileName);
this.getModel().setUploadFilename(scheduleFileName);
this.getModel().setUploadTime(new Date());
this.getClassesService().updateUpload(this.getModel());
return "upload";
}
三、
ClassesService.java
/**
* 更新上传
*
* @param model
*/
public void updateUpload(CrmClasses classes);
ClassesServiceImpl.java
@Override
public void updateUpload(CrmClasses classes) {
// 一、先查询 ,再更新,涉及到快照和一级缓存
CrmClasses findClasses = this.classesDao.findById(classes.getClassesId());
findClasses.setUploadFilename(classes.getUploadFilename());
findClasses.setUploadPath(classes.getUploadPath());
findClasses.setUploadTime(classes.getUploadTime());
}
更新页面的表单须要添加隐藏字段
uploadClass.jsp
<s:form namespace="/" action="classesAction_upload.action" enctype="multipart/form-data">
<!-- <form action="/crm2/classesm/classAction_upload.action" method="post" enctype="multipart/form-data"> -->
<%--添加隐藏字段,由于上传表单的时候,须要先根据id进行查询 --%>
<s:hidden name="classesId" value="%{classesId}"></s:hidden>
<table width="88%" border="0" class="emp_table" style="width:80%;">
四、
struts中拦截器的设置,由于咱们上传的是课表。设置容许上传的文件类型。
<interceptors>
<!-- 2.2.一、声明(注册),将登陆拦截器实现类配置给struts -->
<interceptor name="loginInterceptor" class="com.itheima.crm.web.interceptor.LoginInterceptor"></interceptor>
<!-- 2.2.二、 自定义拦截器栈 -->
<interceptor-stack name="loginStack">
<!-- 给默认的拦截器栈中的某一个拦截器注入内容
* 格式:拦截器名称.属性 值1,值2
allowedExtensions
allowedTypes -->
<interceptor-ref name="defaultStack">
<param name="fileUpload.allowedExtensions">.xls, .xlsx</param>
</interceptor-ref>
<!-- 自定义登陆拦截器:须要配置对login()方法不进行拦截 ,须要进行注入
* excludeMethods 配置不包含的方法,多个方法使用逗号分隔 -->
<interceptor-ref name="loginInterceptor">
<param name="excludeMethods">login</param>
</interceptor-ref>
</interceptor-stack>
五、
文件上传不成功时的页面。使用注解@InputConfig
ClassesAction.java
/**
* 文件(课表)上传
*
* @return
* @throws IOException
*/
@InputConfig(resultName="uploadInput")
public String upload() throws IOException {
struts-classes.xml
<!-- 四、上传不成功页面 -->
<result name="uploadInput">/WEB-INF/pages/error.jsp</result>
六、
文件上传不成功时的错误信息的国际化显示。以下图所示:
界面不友好
<font color="#f00">
系统繁忙,请稍后重试</br>
<s:fielderror></s:fielderror></br>
<%-- <s:actionerror/></br> --%>
<%-- <s:actionmessage/></br> --%>
</font>
界面仍是不友好
struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
struts.xml 的 result 中提供stream类型 inputName 设置 InputStream 得到属性值,须要提供getter方法 contentDisposition 设置 attachment;filename=${imageFileName} 得到文件名称