• 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<Timplements 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<Textends 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<CrmStaffimplements 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<CrmClassesimplements 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="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:learnJavaWebapache-tomcatapache-tomcat-9.0.7webappsday36_06_Spring_crmWEB-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="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-INFlibstruts2-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.4、文件下载

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

  • 相关阅读:
    经典的ajax遍历循环
    fastadmin别名关联表与js下划线冲突问题解决:with里的别名,不要用驼峰,用shippingtype
    thinkphp 临时关闭布局,ajax只输出主题部分
    linux php5.6 链接sql server
    ecstore导入文件开发问题解决 死循环+不兼容mac换行解决
    thinkphp 二级目录安装
    解决crontab执行时间与系统时间不一致的问题
    电阻性能检测的二种方法(转载)
    短路的原因与危害有哪些
    潮湿引发的电路板常见故障(转载)
  • 原文地址:https://www.cnblogs.com/chenmingjun/p/9551705.html
Copyright © 2020-2023  润新知