day37_Spring学习笔记_05_CRM_01

一、CRM 客户关系管理系统

CRM : custom releation manager 客户关系管理系统,用于维护客户和公司之间关系。
我们要做的是:学校 和 大家 之间关系。

  • 完成功能:
  • 员工管理:
    1、登录(登录拦截器、服务器端校验)
    2、查询(普通查询、高级查询)
    3、编辑员工(标签回显、ajax 二级联动)
  • 课程类别:
    1、查询(查询所有 + 条件 + 分页)
    2、添加和编辑
  • 班级管理:
    1、查询
    2、课表的上传、下载
  • 工具类
    1、BaseDao
    2、BaseAction

二、环境搭建

2.1、导入jar包

2.2、创建数据库和表

create database if not exists `day36_crmdb`;
USE `day36_crmdb`;
--------------------------------------------------------
CREATE TABLE `crm_department` (
  `depId` varchar(255NOT NULL PRIMARY KEY,
  `depName` varchar(50DEFAULT NULL
);

insert into `crm_department`(`depId`,`depName`
    values  ('2c9091c14c78e58b014c78e67de10001','java学院'),
            ('2c9091c14c78e58b014c78e68ded0002','咨询部');
--------------------------------------------------------
CREATE TABLE `crm_post` (
  `postId` varchar(255NOT NULL PRIMARY KEY,
  `postName` varchar(100DEFAULT NULL,
  `depId` varchar(255DEFAULT NULL,
  CONSTRAINT FOREIGN KEY (`depId`REFERENCES `crm_department` (`depId`)
);

insert into `crm_post`(`postId`,`postName`,`depId`
    values  ('2c9091c14c78e58b014c78e6b34a0003','总监','2c9091c14c78e58b014c78e67de10001'),
            ('2c9091c14c78e58b014c78e6d4510004','讲师','2c9091c14c78e58b014c78e67de10001'),
            ('2c9091c14c78e58b014c78e6f2340005','主管','2c9091c14c78e58b014c78e68ded0002');
--------------------------------------------------------
CREATE TABLE `crm_staff` (
  `staffId` varchar(255NOT NULL PRIMARY KEY,
  `loginName` varchar(100DEFAULT NULL,
  `loginPwd` varchar(100DEFAULT NULL,
  `staffName` varchar(100DEFAULT NULL,
  `gender` varchar(20DEFAULT NULL,
  `onDutyDate` datetime DEFAULT NULL,
  `postId` varchar(255DEFAULT NULL,
  CONSTRAINT FOREIGN KEY (`postId`REFERENCES `crm_post` (`postId`)
);

insert into `crm_staff`(`staffId`,`loginName`,`loginPwd`,`staffName`,`gender`,`onDutyDate`,`postId`
    values  ('2c9091c14c78e58b014c78e5c32a0000','jack','81dc9bdb52d04dc20036dbd8313ed055','管理员',NULL,NULL,NULL),
            ('2c9091c14c78e58b014c78e759b40006','rose','81dc9bdb52d04dc20036dbd8313ed055','肉丝','女','2013-04-16 00:00:00','2c9091c14c78e58b014c78e6f2340005'),
            ('2c9091c14c78e58b014c78e7ecd90007','tom','81dc9bdb52d04dc20036dbd8313ed055','汤姆','男','2014-04-24 00:00:00','2c9091c14c78e58b014c78e6d4510004');
--------------------------------------------------------
CREATE TABLE `crm_course_type` (
  `courseTypeId` varchar(255NOT NULL PRIMARY KEY,
  `courseCost` double DEFAULT NULL,
  `total` int(11DEFAULT NULL,
  `courseName` varchar(500DEFAULT NULL,
  `remark` varchar(5000DEFAULT NULL
);

insert into `crm_course_type`(`courseTypeId`,`courseCost`,`total`,`courseName`,`remark`
    values  ('2c9091c14c78e58b014c78e829b70008',2000,1000,'java基础',''),
            ('2c9091c14c78e58b014c78e867b80009',18000,4000,'java就业','');
--------------------------------------------------------
CREATE TABLE `crm_classes` (
  `classesId` varchar(50NOT NULL PRIMARY KEY,
  `courseTypeId` varchar(255DEFAULT NULL,
  `name` varchar(50DEFAULT NULL,
  `beginTime` datetime DEFAULT NULL,
  `endTime` datetime DEFAULT NULL,
  `status` varchar(20DEFAULT NULL,
  `totalCount` int(11DEFAULT NULL,
  `upgradeCount` int(11DEFAULT NULL,
  `changeCount` int(11DEFAULT NULL,
  `runoffCount` int(11DEFAULT NULL,
  `remark` varchar(500DEFAULT NULL,
  `uploadTime` datetime DEFAULT NULL,
  `uploadPath` varchar(200DEFAULT NULL,
  `uploadFilename` varchar(100DEFAULT NULL,
  CONSTRAINT FOREIGN KEY (`courseTypeId`REFERENCES `crm_course_type` (`courseTypeId`)
) ;

insert into `crm_classes`(`classesId`,`courseTypeId`,`name`,`beginTime`,`endTime`,`status`,`totalCount`,`upgradeCount`,`changeCount`,`runoffCount`,`remark`,`uploadTime`,`uploadPath`,`uploadFilename`
    values  ('2c9091c14c78e58b014c78e8cc62000a','2c9091c14c78e58b014c78e829b70008','1期','2015-03-10 00:00:00','2015-04-30 00:00:00',NULL,80,2,0,2,'','2015-04-02 16:33:09','/WEB-INF/upload/0d7a042741544da988b2d2462c683e57','(第173期)2015年01月22日 JavaEE就业班.xls'),
            ('2c9091c14c78e58b014c78e9106e000b','2c9091c14c78e58b014c78e829b70008','2期','2015-04-28 00:00:00','2015-05-27 00:00:00',NULL,67,0,0,0,'',NULL,NULL,NULL),
            ('2c9091c14c78e58b014c78e9601a000c','2c9091c14c78e58b014c78e867b80009','1期ee','2015-03-29 00:00:00','2015-07-13 00:00:00',NULL,120,0,0,0,'',NULL,NULL,NULL);

ER图如下:

2.3、项目目录命名规范

com.itheima.crm.子模块.分层
例如:
com.itheima.crm.staff.dao.impl          员工dao层和实现类
com.itheima.crm.staff.service.impl      员工service层和实现类
com.itheima.crm.staff.web.action        员工web
com.itheima.crm.staff.domain            员工javabean

2.4、编写PO类+对应的配置文件Xxx.hbm.xml

仅以 CrmClasses.java、CrmClasses.hbm.xml 和 CrmCourseType.java、CrmCourseType.hbm.xml 为示例:
CrmClasses.java

package com.itheima.crm.classes.domain;

import java.util.Date;

import com.itheima.crm.coursetype.domain.CrmCourseType;

public class CrmClasses {
    /*
        CREATE TABLE `crm_classes` (
          `classesId` varchar(50) NOT NULL PRIMARY KEY,
          `courseTypeId` varchar(255) DEFAULT NULL,
          `name` varchar(50) DEFAULT NULL,
          `beginTime` datetime DEFAULT NULL,
          `endTime` datetime DEFAULT NULL,
          `status` varchar(20) DEFAULT NULL,
          `totalCount` int(11) DEFAULT NULL,
          `upgradeCount` int(11) DEFAULT NULL,
          `changeCount` int(11) DEFAULT NULL,
          `runoffCount` int(11) DEFAULT NULL,
          `remark` varchar(500) DEFAULT NULL,
          `uploadTime` datetime DEFAULT NULL,
          `uploadPath` varchar(200) DEFAULT NULL,
          `uploadFilename` varchar(100) DEFAULT NULL,
          CONSTRAINT FOREIGN KEY (`courseTypeId`) REFERENCES `crm_course_type` (`courseTypeId`)
        ) ;
     */

    private String classesId;
    private String name;            // 班级名称
    private Date beginTime;         // 开班时间
    private Date endTime;           // 毕业时间

    private String status;          // 状态(未开课/已开课/已结束)数据库不需要保存,页面通过计算获得,此字段可以删除
    private Integer totalCount;     // 学生总数
    private Integer upgradeCount;   // 升学数

    private Integer changeCount;    // 转班数(转来)
    private Integer runoffCount;    // 退费数(流失)
    private String remark;          // 其他说明

    private Date uploadTime;        // 上传时间
    private String uploadPath;      // 上传课表路径
    private String uploadFilename;  // 上传课表名称

    // 多对一:多个班级共享【一个课程类别】
    private CrmCourseType courseType;

    // getter 和 setter 方法
    // ......
}

CrmClasses.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">


<hibernate-mapping>
    <class name="com.itheima.crm.classes.domain.CrmClasses" table="crm_classes">
        <id name="classesId">
            <generator class="uuid"></generator>
        </id>

        <property name="name"></property>
        <property name="beginTime" type="date"></property>
        <property name="endTime" type="date"></property>

        <property name="status"></property>
        <property name="totalCount"></property>
        <property name="upgradeCount"></property>

        <property name="changeCount"></property>
        <property name="runoffCount"></property>
        <property name="remark"></property>

        <property name="uploadTime">
            <column name="uploadTime" sql-type="datetime"></column>
        </property>
        <property name="uploadPath"></property>
        <property name="uploadFilename"></property>

        <!-- 多对一:多个班级共享【一个课程类别】  -->
        <many-to-one name="courseType" class="com.itheima.crm.coursetype.domain.CrmCourseType" column="courseTypeId"></many-to-one>
    </class>
</hibernate-mapping>

CrmCourseType.java

public class CrmCourseType {
    /*
        CREATE TABLE `crm_course_type` (
          `courseTypeId` varchar(255) NOT NULL PRIMARY KEY,
          `courseCost` double DEFAULT NULL,
          `total` int(11) DEFAULT NULL,
          `courseName` varchar(500) DEFAULT NULL,
          `remark` varchar(5000) DEFAULT NULL
        );
     */

    private String courseTypeId;
    private Double courseCost;  // 课程费用
    private Integer total;      // 总课时
    private String courseName;  // 课程类别名称
    private String remark;      // 课程介绍模板

    // 一对多:一个课程类别有【多个班级】
    private Set<CrmClasses> classesSet = new HashSet<CrmClasses>();

    // getter 和 setter 方法
    // ......
}

CrmCourseType.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">


<hibernate-mapping>
    <class name="com.itheima.crm.coursetype.domain.CrmCourseType" table="crm_course_type">
        <id name="courseTypeId">
            <generator class="uuid"></generator>
        </id>

        <property name="courseCost"></property>
        <property name="total"></property>
        <property name="courseName"></property>
        <property name="remark"></property>

        <!-- 一对多:一个课程类别有【多个班级】  -->
        <set name="classesSet">
            <key column="courseTypeId"></key>
            <one-to-many class="com.itheima.crm.classes.domain.CrmClasses"/>
        </set>
    </class>
</hibernate-mapping>

2.5、spring 配置

2.5.1、源码文件夹的使用

  • 注意1:如何移除源码文件夹属性
  • 注意2:如何添加源码文件夹属性
  • 注意3:清除classes目录下的文件并再次编译
    选中项目 --> Project --> Clean… --> 选择要清理的项目 --> Ok 即可。

2.5.2、spring 配置文件位置

  • 在applicationContext.xml 中配置其他 applicationContext.-staff.xml 的引用,如下图所示:

2.5.3、web.xml 配置

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
    http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"

    id="WebApp_ID" version="3.1">


    <!-- 1.1、spring配置文件位置 
           方式1: 【建议该方式】
           <param-value>classpath:spring/applicationContext.xml</param-value> 
                需要在applicationContext.xml 配置<import> 导入其他  applicationContext-staff.xml(例如) 文件
           方式2: 
           <param-value>classpath:spring/applicationContext*.xml</param-value> 
                加载所有,不需要配置<import> 导入其他配置文件
    -->

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/applicationContext.xml</param-value>
    </context-param>

    <!-- 1.2、 加载spring配置文件所使用的监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

2.5.4、spring 配置文件内容

applicationContext.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"
>

    <!-- 公共配置项 -->
    <!-- 1.1、加载properties配置文件 -->
    <context:property-placeholder location="classpath:JdbcInfo.properties"/>

    <!-- 1.2、配置数据源,基本四项 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!-- 2、配置 LocalSessionFactoryBean,获得SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
            </props>
        </property>
        <property name="mappingLocations" value="classpath:com/itheima/crm/*/domain/*.hbm.xml"></property>
    </bean>

    <!-- 3、事务管理 -->
    <!-- 3.1、 事务管理器 :HibernateTransactionManager -->
    <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
    <!-- 3.2 、事务详情 ,给ABC进行具体的事务设置 ,增删改:读写,查询:只读-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="add*"/>
            <tx:method name="update*"/>
            <tx:method name="delete*"/>
            <tx:method name="find*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    <!-- 3.3、AOP编程,从 ABCD 业务中 筛选出 ABC,如果强制使用cglib代理 :  proxy-target-class="true" -->
    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.itheima.crm.*.service..*.*(..))"/>
    </aop:config>

    <!-- 导入其他配置文件 -->
    <import resource="applicationContext-staff.xml"/>
</beans>

2.6、struts 配置

2.6.1、struts 配置文件位置

  • struts 的配置文件有一个要求:struts的根文件struts.xml必须放在类路径下,即在源码文件夹下(也即classes目录下)
  • struts.xml 加载其它 struts-staff.xml

struts.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>
    <!-- 1、常量配置 -->
    <!-- 1.1、开发模式 -->
    <constant name="struts.devMode" value="true"></constant>
    <!-- 1.2、标签主题:简单风格 -->
    <constant name="struts.ui.theme" value="simple"></constant>

    <!-- 2 、配置公共项 -->
    <package name="common" namespace="/" extends="struts-default">

    </package>  

    <!-- 3、 加载其他配置文件 -->
    <include file="struts/struts-staff.xml"></include>
</struts>
  • 其他struts-staff.xml配置,继承 struts.xml配置的公共项

struts-staff.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="sta" namespace="/" extends="common">

    </package>  
</struts>

截图如下:


2.6.2、web.xml 配置

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
    http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"

    id="WebApp_ID" version="3.1">


    <!-- 1.1、spring配置文件位置 
           方式1: 【建议该方式】
           <param-value>classpath:spring/applicationContext.xml</param-value> 
                需要在applicationContext.xml 配置<import> 导入其他  applicationContext-staff.xml(例如) 文件
           方式2: 
           <param-value>classpath:spring/applicationContext*.xml</param-value> 
                加载所有,不需要配置<import> 导入其他配置文件
    -->

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/applicationContext.xml</param-value>
    </context-param>

    <!-- 1.2、 加载spring配置文件所使用的监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- 2、struts 前端控制器的配置 -->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>   
</web-app>

2.7、代码编写思路


三、员工登录

思路:
    1. 编写dao层:通过账号和密码查询
    2. 编写service层:主要事务管理(已经配置)
    3. 配置spring
    4. jsp 登录表单
    5. struts-staff.xml 配置
    6. StaffAction编写
        通过service查询
            查询到结果:将信息保存session作用域,重定向首页。(action方法中直接return了,重定向在xml中完成)
            没有结果:在request作用域保存提示信息,请求转发显示提示信息。(在struts中,request作用域 == 值栈) 

3.1、dao 层

  • 注意:之后我们在spring配置dao层时,需要注入SessionFactory。

StaffDao.java

public interface StaffDao {
    /**
     * 通过用户名和密码查询
     * 
     * @param loginName
     * @param loginPwd
     * @return
     */

    public CrmStaff find(String loginName, String loginPwd);
}

StaffDaoImpl.java

public class StaffDaoImpl extends HibernateDaoSupport implements StaffDao {

    @Override
    public CrmStaff find(String loginName, String loginPwd) {
        List<CrmStaff> allStaff = this.getHibernateTemplate().find("from crm_staff where loginName=? and loginPwd=?", loginName, loginPwd);
        if (allStaff.size() == 1) {
            return allStaff.get(0);
        }
        return null;
    }
}

3.2、service 层

StaffService.java

public interface StaffService {
    /**
     * 用户登录
     * 
     * @param staff
     * @return
     */

    public CrmStaff login(CrmStaff staff);
}

StaffServiceImpl.java

public class StaffServiceImpl implements StaffService {

    private StaffDao staffDao;
    public void setStaffDao(StaffDao staffDao) {
        this.staffDao = staffDao;
    }

    @Override
    public CrmStaff login(CrmStaff staff) {
        return staffDao.find(staff.getLoginName(), staff.getLoginPwd());
    }
}

3.3、spring 配置

applicationContext-staff.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="staffDao" class="com.itheima.crm.staff.dao.impl.StaffDaoImpl">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
    <bean id="staffService" class="com.itheima.crm.staff.service.impl.StaffServiceImpl">
        <property name="staffDao" ref="staffDao"></property>
    </bean>
</beans>

3.4、jsp 文件位置

  • 实际开发中,所有的jsp页面在WEB-INF目录下。(因为这样,就不能通过浏览器直接访问它们了)
  • 例如:WEB-INF/pages/模块/*.jsp,如下图所示:

3.5、修改登录表单

  • 登录表单位置:/day36_06_Spring_crm/WebRoot/WEB-INF/pages/login.jsp
  • 表单是否需要struts标签(<%@ taglib uri="/struts-tags" prefix="s"%>),取决于:是否回显。要回显,就需要struts标签。

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<STYLE>
.cla1 {
FONT-SIZE12pxCOLOR#4b4b4bLINE-HEIGHT18pxTEXT-DECORATION: none
}
.login_msg{
    font-family:serif;
}
.login_msg .msg{
    background-color#acf;
}
.login_msg .btn{
    background-color#9be;
    width73px;
    font-size18px;
    font-family: 微软雅黑;
}
</STYLE>

<TITLE></TITLE>
    <script type="text/javascript">
        if(self != top){
            top.location = self.location;
        }
    
</script>
<META http-equiv=Content-Type content="text/html; charset=utf-8">
<LINK href="${pageContext.request.contextPath}/css/style.css" type=text/css rel=stylesheet>
<META content="MSHTML 6.00.2600.0" name=GENERATOR></HEAD>
<BODY leftMargin=0 topMargin=0 marginwidth="0" marginheight="0" background="${pageContext.request.contextPath}/images/rightbg.jpg">
<div ALIGN="center">
    <table border="0" width="1140px" cellspacing="0" cellpadding="0" id="table1">
        <tr>
            <td height="93"></td>
            <td></td>
        </tr>
        <tr>
            <td background="${pageContext.request.contextPath}/images/right.jpg"  width="740" height="412"></td>
            <td class="login_msg" width="400">
                <!-- 表单 -->
                <s:form namespace="/" action="staffAction_login">
                    &nbsp;<img src="${pageContext.request.contextPath}/images/title.png" width="185" height="26"/>
                    <br/>
                    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                    <font color="#ff0000">
                        <s:fielderror></s:fielderror>
                    </font> 
                    <br/>
                    用户名:<s:textfield name="loginName" cssClass="msg"></s:textfield><br/><br/>
                    密&nbsp;码:<s:password name="loginPwd" cssClass="msg" showPassword="true"></s:password><br/><br/>
                    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                    <s:submit value="登录" cssClass="btn"></s:submit>         
                </s:form>
                <!-- 
                <form action="${pageContext.request.contextPath}/pages/frame.jsp" method="post">
                    &nbsp;<img src="${pageContext.request.contextPath}/images/title.png" width="185" height="26"/>
                    <br/>
                    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                    <font color="#ff0000">
                        错误提示
                    </font> 
                    <br/>
                    用户名:<input type="text" name="loginName" class="msg" /><br/><br/>
                    密&nbsp;码:<input type="password" class="msg" /><br/><br/>
                    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                    <input type="submit" class="btn" value="登录 " />
                </form>
                -->


                <!-- jsp的页面,作用:测试用,用完后删除掉-->
                <a href="${pageContext.request.contextPath}/pages/frame.jsp">jsp页面</a>
            </td>
        </tr>
    </table>

    <script type="text/javascript">
        /* s标签中直接编写JavaScript代码时,不支持el表达式,只能提供单独的函数
        function registerUrl() {
            document.location='${pageContext.request.contextPath}/uiAction_staff_register';
        }
        */

    
</script>
</div>
</BODY></HTML>

3.6、struts-staff.xml 配置

  • /day36_06_Spring_crm/config/struts/struts-staff.xml

struts-staff.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="sta" namespace="/" extends="common">
        <action name="staffAction_*" class="com.itheima.crm.staff.web.action.StaffAction" method="{1}">
            <!-- 1、登录成功 -->
            <result name="success" type="redirectAction">staffAction_home</result>
            <!-- 2、登录不成功,需要重新登录 -->
            <result name="login">/WEB-INF/pages/login.jsp</result>
            <!-- 3、返回 首页-->
            <result name="home">/WEB-INF/pages/frame.jsp</result>
        </action>
    </package>  
</struts>

3.7、Action实现类

StaffAction.java

public class StaffAction extends ActionSupport implements ModelDriven<CrmStaff{

    // ****************************************************************
    // 公共代码

    // 封装数据
    private CrmStaff staff = new CrmStaff();

    @Override
    public CrmStaff getModel() {
        return staff;
    }

    // 默认按照名称进行注入
    private StaffService staffService;
    public void setStaffService(StaffService staffService) {
        this.staffService = staffService;
    }

    // ****************************************************************
    // 业务代码(功能代码)

    /**
     * 员工登录 
     * 
     * @return
     */

    public String login() {
        // 1、查询员工
        CrmStaff findStaff = staffService.login(staff);

        // 2、判断是否成功
        if (findStaff != null) {
            // 登录成功
            // 3.1、把数据保存在session作用域
            ActionContext.getContext().getSession().put("loginStaff", findStaff);
            // 3.2、重定向至首页,需要在 struts-staff.xml 中进行配置
            return "success";
        }
        // 4、登录不成功,添加错误显示信息
        this.addFieldError("""登录名或密码错误");
        // 5、请求转发显示
        return "login";
    }

    /**
     * 显示首页
     * 
     * @return
     */

    public String home() {
        return "home";
    }
}

3.8、密码加密

  • /day36_06_Spring_crm/src/com/itheima/crm/utils/MyStringUtils.java

编写我的工具类
MyStringUtils.java

public class MyStringUtils {
    /**
     * 获得MD5加密后的数据
     * 
     * @param value 明文
     * @return  密文
     */

    public static String getMD5Value(String value{

        try {
            // 1、获得jdk所提供的消息摘要算法的工具类
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            // 2、加密操作,加密的结果是十进制,需要转换为16进制
            byte[] md5ValueByteArray =  messageDigest.digest(value.getBytes());
            BigInteger bigInteger = new BigInteger(1, md5ValueByteArray);

            return bigInteger.toString(16);
        } catch (NoSuchAlgorithmException e) {
            // 法一:抛出异常
            throw new RuntimeException(e);
            // 法二:如果出现了异常,将返回默认值
            // return value;
        }
    }
}
  • 修改service层代码
package com.itheima.crm.staff.service.impl;

import com.itheima.crm.staff.dao.StaffDao;
import com.itheima.crm.staff.domain.CrmStaff;
import com.itheima.crm.staff.service.StaffService;
import com.itheima.crm.utils.MyStringUtils;

public class StaffServiceImpl implements StaffService {

    private StaffDao staffDao;
    public void setStaffDao(StaffDao staffDao) {
        this.staffDao = staffDao;
    }

    @Override
    public CrmStaff login(CrmStaff staff) {
        // MD5加密操作
        String loginPwd = MyStringUtils.getMD5Value(staff.getLoginPwd());
        return staffDao.find(staff.getLoginName(), loginPwd);
    }
}

四、UiAction

  • 配置公共jsp访问的action

struts.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>
    <!-- 1、常量配置 -->
    <!-- 1.1、开发模式 -->
    <constant name="struts.devMode" value="true"></constant>
    <!-- 1.2、标签主题:简单风格 -->
    <constant name="struts.ui.theme" value="simple"></constant>

    <!-- 2 、配置公共项 -->
    <package name="common" namespace="/" extends="struts-default">
    <!-- 2.1、配置公共jsp访问的action 
        版本1:通过自定义action实现,自定义的action继承父类ActionSupport
            <action name="uiAction" class="com.itheima.crm.web.action.UiAction">
                <result name="success">/WEB-INF/pages/frame/top.jsp</result>
            </action>

        版本2:直接通过父类ActionSupport
            <action name="uiAction" class="com.opensymphony.xwork2.ActionSupport">
                <result name="success">/WEB-INF/pages/frame/top.jsp</result>
            </action>

            能否将class属性删除呢? 因为class属性的默认值就是“ActionSupport”  
            <action name="uiAction">
                <result name="success">/WEB-INF/pages/frame/top.jsp</result>
            </action>

            name属性值也可以删除掉,因为其默认值也是“success”
            <action name="uiAction">
                <result>/WEB-INF/pages/frame/top.jsp</result>
            </action>

        版本3:使用通配符
            <action name="uiAction_*_*">
                <result>/WEB-INF/pages/{1}/{2}.jsp</result>
            </action>

            uiAction_*_*
                第一个星匹配的是文件夹的名称,通过{1}获取
                第二个星匹配的是jsp文件名称,通过{2}获取
            例如:
                uiAction_frame_top 匹配的是  /WEB-INF/pages/frame/top.jsp
        -->

        <action name="uiAction_*_*">
            <result>/WEB-INF/pages/{1}/{2}.jsp</result>
        </action>
    </package>  

    <!-- 3、 加载其他配置文件 -->
    <include file="struts/struts-staff.xml"></include>
</struts>

五、登录拦截器

  • 必须是登录状态,才能访问首页,否则不能访问。
  • 回顾登录拦截器实现类
  • struts中的配置
    1. 先注册,将登录拦截器实现类配置给struts
    2. 再使用
      2.1 每一个action单独使用登录拦截器
      2.2 将多个拦截器打包生成自定义栈,在action中使用自定义栈
      2.3 使用自定义的栈,把默认的栈覆盖(即把自定义栈声明成默认的栈)
  • 功能:判断session作用域中是否有用户信息,如果有就放行,如果没有就拦截掉。

5.1、实现类

LoginInterceptor.java

public class LoginInterceptor extends MethodFilterInterceptor {

    @Override
    protected String doIntercept(ActionInvocation invocation) throws Exception {
        // 判断session作用域中是否有用户信息,如果有就放行,如果没有就拦截掉。
        CrmStaff crmStaff = (CrmStaff) ActionContext.getContext().getSession().get("loginStaff");
        if (crmStaff == null) {
            // 同理:StaffAction.java中的login()方法一样:
            // 1、获得当前运行的action
            Object action = invocation.getAction();
            // 2、判断:在运行时的action对象是否是ActionSupport对象
            if (action instanceof ActionSupport) {
                // 如果是,就进行强转
                ActionSupport actionSupport = (ActionSupport) action;
                // 4、登录不成功,添加错误显示信息
                actionSupport.addFieldError("""请重新登录");
            }

            // 没有登录,需要登录
            return "login";
        }
        // 已经登录了,就放行
        return invocation.invoke();
    }
}

5.2、struts.xml 中的配置

struts.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>
    <!-- 1、常量配置 -->
    <!-- 1.1、开发模式 -->
    <constant name="struts.devMode" value="true"></constant>
    <!-- 1.2、标签主题:简单风格 -->
    <constant name="struts.ui.theme" value="simple"></constant>

    <!-- 2 、配置公共项 -->
    <package name="common" namespace="/" extends="struts-default">
        <!-- 2.2、登录拦截器的配置 
            前提:都要先声明
            方式一:每一个action单独使用登录拦截器,需要多次引用,否则默认的拦截器将被覆盖
                <action name="uiAction_*_*">
                    <result>/WEB-INF/pages/{1}/{2}.jsp</result>
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                    <interceptor-ref name="loginInterceptor"></interceptor-ref>
                </action>

            方式二:将多个拦截器打包生成自定义栈,在action中使用自定义栈
                <interceptor-stack name="loginStack">
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                    <interceptor-ref name="loginInterceptor"></interceptor-ref>
                </interceptor-stack>                

                <action name="uiAction_*_*">
                    <result>/WEB-INF/pages/{1}/{2}.jsp</result>
                    <interceptor-ref name="loginStack"></interceptor-ref>
                </action>

            方式三:使用自定义的栈,把默认的栈覆盖(即把自定义栈声明成默认的栈)
                <default-interceptor-ref name="loginStack"></default-interceptor-ref>

                <action name="uiAction_*_*">
                    <result>/WEB-INF/pages/{1}/{2}.jsp</result>
                    <interceptor-ref name="loginStack"></interceptor-ref>
                </action>
        -->

        <interceptors>
            <!-- 2.2.1、声明(注册),将登录拦截器实现类配置给struts -->
            <interceptor name="loginInterceptor" class="com.itheima.crm.web.interceptor.LoginInterceptor"></interceptor>
            <!-- 2.2.2、 自定义拦截器栈 -->
            <interceptor-stack name="loginStack">
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <!-- 自定义登录拦截器:需要配置对login()方法不进行拦截 
                    * excludeMethods 配置不包含的方法,多个方法使用逗号分隔
                -->

                <interceptor-ref name="loginInterceptor">
                    <param name="excludeMethods">login</param>
                </interceptor-ref>
            </interceptor-stack>
        </interceptors>

        <!-- 2.2.3、 使用自定义的栈,把默认的栈覆盖(即把自定义栈声明成默认的栈)-->
        <default-interceptor-ref name="loginStack"></default-interceptor-ref>
        <!-- 2.2.4、配置全局结果集 -->
        <global-results>
            <result name="login">/WEB-INF/pages/login.jsp</result>
        </global-results>

        <!-- 2.1、配置公共jsp访问的action -->
        <action name="uiAction_*_*">
            <result>/WEB-INF/pages/{1}/{2}.jsp</result>
            <interceptor-ref name="loginStack"></interceptor-ref>
        </action>
    </package>  

    <!-- 3、 加载其他配置文件 -->
    <include file="struts/struts-staff.xml"></include>
</struts>

5.3、登录拦截器总结图解

六、查询所有员工

思路:
    1. dao层:findAll()
    2. service层:findAllStaff()
    3. action类:findAll() --> staffAction_findAll
    4. jsp页面:显示数据

6.1、dao 层

StaffDao.java

    /**
     * 查询所有员工
     * 
     * @return
     */

    public List<CrmStaff> findAll();

StaffDaoImpl.java

    @Override
    public List<CrmStaff> findAll() {
        return this.getHibernateTemplate().find("from CrmStaff");
    }

6.2、service层

StaffService.java

    /**
     * 查询所有员工
     * 
     * @return
     */

    public List<CrmStaff> findAllStaff();

StaffServiceImpl.java

    @Override
    public List<CrmStaff> findAllStaff() {
        return this.staffDao.findAll();
    }

6.3、jsp入口

  • 文件位置:/day36_06_Spring_crm/WebRoot/WEB-INF/pages/frame/left.jsp

6.4、action类

StaffAction.java

......
    /**
     * 查询所有员工
     * 
     * @return
     */

    public String findAll() {
        // 1、查询所有员工
        List<CrmStaff> allStaff = staffService.findAllStaff();
        // 2、将查询的结果放入值栈中,以方便jsp页面获得数据(原则:无论你怎么放,页面上能取的出来就行)
        // 方式一:context(大map中),使用put(key, value) 方法,jsp页面使用 “#key” 方式获得
        //      示例:ActionContext.getContext().put(key, value);
        // 方式二:root(值栈中),使用push(Object)方法,一般我们的查询结果为javabean 或者 为Map时,jsp页面使用 “属性”或者“key”    方式获得
        //      示例:ActionContext.getContext().getValueStack().push(obj);
        // 方式三:root(值栈中),使用set(key, value),一般我们的查询的结果为 集合List 时,jsp页面使用 “key” 方式获得
        //      注意:set(key, value) 的底层使用的是 new Map(key, value),再将Map集合 push(Map)

        // 这里我们使用方式一
        ActionContext.getContext().put("allStaff", allStaff);

        return "findAll";
    }
......

6.5、jsp展示

  • 文件位置:/day36_06_Spring_crm/WebRoot/WEB-INF/pages/staff/listStaff.jsp

  • debug调试结果:

6.6、web.xml 配置过滤器

  • OpenSessionInViewFilter,作用:延迟关闭session

注意:必须配置在struts 的前端控制器之前

    <!-- 配置spring 过滤器,延时session的关闭 -->
    <filter>
        <filter-name>OpenSession</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>OpenSession</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
  • 查询所有员工截图:
posted @ 2018-08-15 19:47 黑泽君 阅读(...) 评论(...) 编辑 收藏