day39_Spring学习笔记_07_CRM_03

十、课程类别的分页(含条件)

10.1、流程分析

10.2、PageBean 实现分析

  PageBean.java

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;

        // 计算项
        // 1、开始索引(索引从0开始)
        this.startIndex = (this.pageNum -1) * this.pageSize;
        // 2、总分页数
        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;
    }
}

10.3、dao层 实现分析

  自定义实现类   PageHibernateCallback.java

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.1、首先,只要setter方法,不要getter方法
    // 5.2、返回值类型是自己,返回的是自己
    // 5.3、使用时,先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 {
        // 1、通过HQL语句,获得Query对象
        Query queryObject = session.createQuery(hql);
        // 2、条件设置
        for (int i = 0; i < params.length; i++) {
            queryObject.setParameter(i, params[i]);
        }
        // 3、分页
        queryObject.setFirstResult(startIndex);
        queryObject.setMaxResults(pageSize);
        // 4、查询所有
        return queryObject.list();
    }
}

  CourseTypeDao.java

    /**
     * 分页,查询总记录数
     * 
     * @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.java

    @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)); 
    }

10.4、service层 实现分析

  CourseTypeService.java

    /**
     * 带有条件的查询所有课程类别  + 分页
     * 
     * @param courseType 条件
     * @param pageNum 第几页(当前页)
     * @param pageSize 每页显示个数
     * @return
     */
    public PageBean<CrmCourseType> findAllCourseType(CrmCourseType courseType, int pageNum, int pageSize);

  CourseTypeServiceImpl.java

    @Override
    public PageBean<CrmCourseType> findAllCourseType(CrmCourseType courseType, int pageNum, int pageSize) {
        // 1.1、使用StringBuilder 接收:拼凑查询条件
        StringBuilder builder = new StringBuilder();
        // 1.2、使用List 接收:拼凑实际参数,需要可以重复,有顺序  => 选择  List集合
        List<Object> paramsList = new ArrayList<Object>();

        // 2、过滤条件
        // 2.1、过滤课程类别,不需要 null 或者 "" 或者 "  ",使用工具类
        if (StringUtils.isNotBlank(courseType.getCourseName())) {
            builder.append(" and courseName like ?");
            paramsList.add("%" + courseType.getCourseName() + "%");
        }
        // 2.2、过滤课程简介,不需要 null 或者 "" 或者 "  ",使用工具类
        if (StringUtils.isNotBlank(courseType.getRemark())) {
            builder.append(" and remark like ?");
            paramsList.add("%" + courseType.getRemark() + "%");
        }
        // 2.3、过滤总学时
        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.3、过滤总费用
        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()));
        }

        // 3、使用数据
        // 1、条件,格式:“and ...? and ...?”
        String condition = builder.toString();
        // 2、实际参数
        Object[] params = paramsList.toArray();

        // 2、分页
        // 2.1、总记录数 totalRecord
        int totalRecord = this.courseTypeDao.getTotalRecord(condition, params);
        // 2.2、创建PageBean对象
        PageBean<CrmCourseType> pageBean = new PageBean<CrmCourseType>(pageNum, pageSize, totalRecord);
        // 2.3、分页数据
        List<CrmCourseType> data = this.courseTypeDao.findAll(condition, params, pageBean.getStartIndex(), pageBean.getPageSize());
        pageBean.setData(data);

        return pageBean;
    }

10.5、jsp页面 实现分析

  • 方案1
  • 方案2

我们使用方案2。

  /day36_06_Spring_crm/WebRoot/WEB-INF/pages/coursetype/listCourse.jsp

......
<%--条件查询 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>&nbsp;&nbsp; <%-- 首页 = 1 --%>
                <a href="javascript:void(0)" onclick="showPage(<s:property value="#pageBean.pageNum - 1"/>)">[上一页]</a>&nbsp;&nbsp; <%-- 上一页 = 当前页 - 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>&nbsp;&nbsp; <%-- 下一页 = 当前页 + 1 --%>
                <a href="javascript:void(0)" onclick="showPage(<s:property value="#pageBean.totalPage"/>)">[尾页]</a>&nbsp;&nbsp; <%-- 尾页 --%>
            </s:if>
        </span>
    </td>
  </tr>
</table>
    <script type="text/javascript">
        function showPage(num) {
            // 1、修改隐藏域的值
            document.getElementById("pageNum").value = num;
            // 2、提交表单
            document.forms[0].submit();
        }
    </script>
......

10.6、jsp页面 动态显示效果

  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;

        // 计算项
        // 1、开始索引(索引从0开始)
        this.startIndex = (this.pageNum -1) * this.pageSize;
        // 2、总分页数
        this.totalPage = (this.totalRecord + (this.pageSize - 1)) / this.pageSize;

        // 3、增加动态显示条
        // 3.1、初始化数据,暂定显示10个分页
        this.start = 1; // 开始的分页
        this.end = 10; // 最后的分页

        // 3.2、处理数据,假如:总分页数 totalPage = 4
        if (this.totalPage <= 10) {
            this.end = this.totalPage; // 最后的分页=总分页数
        } else {
            // 假如:总分页数 totalPage = 15

            // 3.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.jsp

......
            <s:if test="#pageBean.pageNum gt 1"><%--gt 等价于 < --%>
                <a href="javascript:void(0)" onclick="showPage(1)">[首页]</a>&nbsp;&nbsp; <%-- 首页 = 1 --%>
                <a href="javascript:void(0)" onclick="showPage(<s:property value="#pageBean.pageNum - 1"/>)">[上一页]</a>&nbsp;&nbsp; <%-- 上一页 = 当前页 - 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>&nbsp;&nbsp;
            </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>&nbsp;&nbsp; <%-- 下一页 = 当前页 + 1 --%>
                <a href="javascript:void(0)" onclick="showPage(<s:property value="#pageBean.totalPage"/>)">[尾页]</a>&nbsp;&nbsp; <%-- 尾页 --%>
            </s:if>
......

十一、this小案例

  Parent.java

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.java

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

十二、BaseDao

以前的做法:

现在的做法:

    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;
    }
}

十三、BaseAction

主要思想:
    1、封装数据
    2、让Spring一下子注入多个service
    3、分页的数据
    4、简化值栈操作

  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> {

    // 1、封装数据
    private T t;

    @Override
    public T getModel() {
        return t;
    }

    // 1.1、实例化T,可以通过反射去new出T
    public BaseAction() {
        try {
            // 1、要先获得该类运行时的Class
            ParameterizedType parameterizedType =  (ParameterizedType) this.getClass().getGenericSuperclass();
            Class<T> clazz = (Class<T>) parameterizedType.getActualTypeArguments()[0];
            // 2、通过反射去创建实例
            t = clazz.newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e); // 把编译时异常转换成运行时异常
        }
    }

    // 2、让Spring一下子注入多个service
    // 提供setter方法,是让Spring进行注入的
    // 提供getter方法,是让子类可以获得Spring注入的对象的

    // 2.1、员工的service
    private StaffService staffService;
    public void setStaffService(StaffService staffService) {
        this.staffService = staffService;
    }
    public StaffService getStaffService() {
        return staffService;
    }
    // 2.2、职务的service
    private PostService postService;
    public void setPostService(PostService postService) {
        this.postService = postService;
    }
    public PostService getPostService() {
        return postService;
    }
    // 2.3、部门的service
    private DepartmentService departmentService;
    public void setDepartmentService(DepartmentService departmentService) {
        this.departmentService = departmentService;
    }
    public DepartmentService getDepartmentService() {
        return departmentService;
    }
    // 2.4、课程类别的service
    private CourseTypeService courseTypeService;
    public void setCourseTypeService(CourseTypeService courseTypeService) {
        this.courseTypeService = courseTypeService;
    }
    public CourseTypeService getCourseTypeService() {
        return courseTypeService;
    }
    // 2.5、班级的service

    // 3、分页的数据
    // 第几页(当前页)
    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;
    }

    // 4、简化值栈操作
    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);
    }
}

十四、上传和下载

14.1、班级列表的查询

思路:
    1. ClassesDao / ClassesDaoImpl --> 继承BaseDao / BaseDaoImpl
    2. service
    3. spring配置,完善BaseAction
    4. ClassesAction --> 继承BaseAction
    5. left.jsp --> struts.xml/struts-classes.xml --> listClass.jsp

1、   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 {

}

2、   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();
    }
}

3、   applicationContext.xml

    <!-- 4.5、班级 -->
    <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.5、班级的service
    private ClassesService classesService;
    public void setClassesService(ClassesService classesService) {
        this.classesService = classesService;
    }
......

4、   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";
    }
}

5、   /day36_06_Spring_crm/WebRoot/WEB-INF/pages/frame/left.jsp

        d.add('010301','0103','班级管理','${pageContext.request.contextPath}/classesAction_findAll','','right');

  struts.xml

    <!-- 3.4、班级-->
    <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}">
            <!-- 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>
......

14.2、通过班级id查询班级详情

  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

            <!-- 2、显示上传表单页面 -->
            <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>&nbsp;</td>
      </tr>
      <tr>
        <td>班级:</td>
        <td><s:property value="name"/></td>
        <td>&nbsp;</td>
      </tr>
      <tr>
        <td>上次上传时间:</td>
        <td><s:date name="uploadTime"/></td>
        <td>&nbsp;</td>
      </tr>
      <tr>
        <td>选择课表:</td>
        <td>&nbsp;</td>
        <td>&nbsp;</td>
      </tr>
      <tr>
        <td colspan="3">
            <input type="file" name="schedule" value="" />
        </td>
      </tr>
    </table>
......

14.3、文件上传

    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. 文件上传不成功时的错误信息的国际化显示。

1、

  uploadClass.jsp

......
<s:form namespace="/" action="classAction_upload.action" enctype="multipart/form-data">
......
<s:file name="schedule"></s:file>
......

2、   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、将课表保存在硬盘(企业级开发中,图片会上传到图片服务器,图片服务器返回一个路径,我们把该路径保存在数据库中即可)
        // 1.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.2、我们希望文件名是一个32位的随机数,且没有扩展名,这样安全性更高
        String fileName = MyStringUtils.getUUID();
        // 1.3、保存操作
        FileUtils.copyFile(schedule, new File(parentDir, fileName));

        // 2、更新操作
        this.getModel().setUploadPath("/WEB-INF/upload" + fileName);
        this.getModel().setUploadFilename(scheduleFileName);
        this.getModel().setUploadTime(new Date());

        this.getClassesService().updateUpload(this.getModel());

        return "upload";
    }

3、   ClassesService.java

    /**
     * 更新上传
     * 
     * @param model
     */
    public void updateUpload(CrmClasses classes);

  ClassesServiceImpl.java

    @Override
    public void updateUpload(CrmClasses classes) {
        // 1、先查询 ,再更新,涉及到快照和一级缓存
        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%;">

4、   struts中拦截器的设置,因为我们上传的是课表。设置允许上传的文件类型。

        <interceptors>
            <!-- 2.2.1、声明(注册),将登录拦截器实现类配置给struts -->
            <interceptor name="loginInterceptor" class="com.itheima.crm.web.interceptor.LoginInterceptor"></interceptor>
            <!-- 2.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>

5、   文件上传不成功时的页面。使用注解@InputConfig   ClassesAction.java

            /**
             * 文件(课表)上传
             * 
             * @return
             * @throws IOException
             */
            @InputConfig(resultName="uploadInput")
            public String upload() throws IOException {

  struts-classes.xml

            <!-- 4、上传不成功页面 -->
            <result name="uploadInput">/WEB-INF/pages/error.jsp</result>

6、   文件上传不成功时的错误信息的国际化显示。如下图所示:   界面不友好

  在error.jsp中,添加错误信息提示

    <font color="#f00">
        系统繁忙,请稍后重试</br>
        <s:fielderror></s:fielderror></br>
        <%-- <s:actionerror/></br> --%>
        <%-- <s:actionmessage/></br> --%>
    </font>

  界面还是不友好

  需要进行国际化显示,在com.itheima.crm.classes.web.action包中新建ClassesAction.properties文件,   打开:\WEB-INF\lib\struts2-core-2.3.15.3.jar/org/apache/struts2/struts-messages.properties该文件,   复制 struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}   该句代码至ClassesAction.properties文件中,进行修改,如下图所示:

  效果如下:

14.3、文件下载

  struts.xml 的 result 中提供stream类型     inputName 设置 InputStream 获得属性值,需要提供getter方法     contentDisposition 设置 attachment;filename=${imageFileName} 获得文件名称

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java Web

初学Java Web(9)——学生管理系统(简易版)总结

项目开始时间:2018年4月8日14:37:47 项目完成时间:2018年4月9日10:03:30 技术准备 这个项目是自己用于巩固 J2EE 相关知识的练...

6375
来自专栏Java学习网

常见的 Java 错误及避免方法之第五集(每集10个错误后续持续发布)

当输入期间意外终止文件或流时,将抛出“EOFException”。 以下是抛出EOFException异常的一个示例,来自JavaBeat应用程序:

1503
来自专栏微信公众号:Java团长

SSM框架——实现分页和搜索分页

分页是Java Web项目常用的功能,昨天在Spring MVC中实现了简单的分页操作和搜索分页,在此记录一下。使用的框架为(MyBatis+SpringMVC...

2434
来自专栏大前端_Web

easyUI组件datagrid的二次封装

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/articl...

2533
来自专栏cmazxiaoma的架构师之路

通用Mapper和PageHelper插件 学习笔记

9643
来自专栏微服务那些事儿

关键数据变更监控

在经过了对mybatis的一番检索之后,没有发现对该需求的解决方式.在认知范围内,想到了使用mabatis拦截器解决该问题。

82019
来自专栏java一日一条

50个常见的 Java 错误及避免方法(第三部分)

当我们尝试调用带有错误参数的Java代码时,通常会产生此Java错误消息(@ghacksnews):

1473
来自专栏Kubernetes

runC源码分析——namespace

runc/libcontainer/configs/config.go中定义了container对应的Namespaces。另外对于User Namespace...

3758
来自专栏Flutter入门

Weex是如何在Android客户端上跑起来的

Weex可以通过自己设计的DSL,书写.we文件或者.vue文件来开发界面,整个页面书写分成了3段,template、style、script,借鉴了成熟的MV...

4245
来自专栏.NET开发那点事

IoC原理-使用反射/Emit来实现一个最简单的IoC容器

从Unity到Spring.Net,到Ninject,几年来陆陆续续用过几个IoC框架。虽然会用,但也没有一直仔细的研究过IoC实现的过程。最近花了点时间,下了...

22610

扫码关注云+社区

领取腾讯云代金券