本文来自我的ssm博客: http://iclyj.cn
首先什么叫做CRM呢?
CRM : custom releation manager 客户关系管理系统,用于维护客户和公司之间关系
学校 和 大家 之间关系
完成功能:
员工管理
1. 登录(登录拦截器、服务器端校验)
2. 查询
3. 编辑员工(标签回显、ajax 二级联动)
课程类别
1.查询 (查询所有 + 条件 + 分页)
2. 添加和编辑
班级管理
1.查询
2.课表 上传、下载
工具类
BaseDao
BaseAction
1 环境搭建
1.1 导入jar包
![](https://img-blog.csdn.net/20170518210531649?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1.2 数据库和表
![](https://img-blog.csdn.net/20170518210617634?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1.1 目录规范
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
1.1 编写PO类
![](https://img-blog.csdn.net/20170518212126250?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1.2 spring 配置
1.2.1 源码文件夹
![](https://img-blog.csdn.net/20170518212244157?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20170518212330485?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1.2.2 spring 配置文件位置
![](https://img-blog.csdn.net/20170518212513643?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
在applicationContext.xml 配置其他 xml引用
![](https://img-blog.csdn.net/20170518212517815?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1.2.3 web.xml配置
<!-- 1.1 spring配置文件位置
* 方式1: 【建议】
<param-value>classpath:spring/applicationContext.xml</param-value>
需要在applicationContext.xml 配置<import> 导入其他
* 方式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>
|
1.2.4 spring配置内容
<!-- 公共配置项 -->
<!-- 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. 配置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 事务管理器 -->
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 3.2 事务详情
* 增删改:读写;查询:只读
-->
<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编程
* 强制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"/>
|
1.3 struts 配置
1.3.1 配置文件位置
![](https://img-blog.csdn.net/20170518212802363?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
struts.xml 加载其他 xml
![](https://img-blog.csdn.net/20170518212928224?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
其他xml 配置 ,继承 struts.xml配置的公共项
![](https://img-blog.csdn.net/20170518212957820?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20170518213025571?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1.3.2 web.xml配置
<!-- 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>
|
1.3.3 编写思路
![](https://img-blog.csdn.net/20170518213112599?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
2 员工登录
1.编写dao层:通过账号和密码查询
2.编写service层:主要事务管理(已经配置)
3.配置spring
4.jsp 登录表单
5.struts-staff.xml 配置
6.StaffAction编写
通过service查询
查询到:将信息保存session作用域,重定向首页(action方法直接return,重定向在xml完成)
没有结果:在request作用域保存提示信息,请求转发显示信息。(request作用域== 值栈)
2.1 dao层
之后在spring配置dao层时,需要注入SessionFactory
public class StaffDaoImpl extends HibernateDaoSupport 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;
}
}
|
2.2 service层
public class StaffServiceImpl implements StaffService {
private StaffDao staffDao;
public void setStaffDao(StaffDao staffDao) {
this.staffDao = staffDao;
}
@Override
public CrmStaff login(CrmStaff staff) {
//TODO MD5加密
return staffDao.find(staff.getLoginName(), staff.getLoginPwd());
}
}
|
2.3 spring配置
<!-- 员工配置项: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>
|
2.4 jsp文件位置
所有的jsp页面存在WEB-INF目录下。 (不能通过浏览器直接访问)
WEB-INF/page/模块/*.jsp
![](https://img-blog.csdn.net/20170518213355576?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
2.5 修改登录表单
/ee19_crm/WebRoot/WEB-INF/pages/login.jsp
表单是否需要struts标签,取决于:是否回显。
<!-- 表单 -->
<s:form namespace="/" action="staffAction_login" >
<img src="${pageContext.request.contextPath}/images/title.png" width="185" height="26"/>
<br/>
<font color="#ff0000">
<s:fielderror></s:fielderror>
</font>
<br/>
用户名:<s:textfield name="loginName" cssClass="msg"></s:textfield><br/><br/>
密 码:<s:password name="loginPwd" cssClass="msg" showPassword="true"></s:password><br/><br/>
<s:submit value="登录" cssClass="btn"></s:submit>
</s:form>
|
2.6 struts-staff.xml配置
/ee19_crm/config/struts/struts-staff.xml
<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>
|
2.7 Action实现类
2.7.1 公共
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;
}
|
2.7.2 功能
/**
* 员工登录
* @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 重定向首页 -- xml配置
return "success";
}
//4 不成功
this.addFieldError("", "用户名与密码不匹配");
// * 请求转发显示
return "login";
}
/**
* 显示首页
* @return
*/
public String home(){
return "home";
}
|
2.8 密码加密
/**
* 获得md5加密后的数据
* @param value 明文
* @return 密文
*/
public static String getMD5Value(String value){
try {
//1 获得jdk提供消息摘要算法工具类
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
//2 加密的结果10进制
byte[] md5ValueByteArray = messageDigest.digest(value.getBytes());
//3将10进制 转换16进制
// System.out.println(Arrays.toString(md5ValueByteArray));
BigInteger bigInteger = new BigInteger(1 , md5ValueByteArray);
return bigInteger.toString(16);
} catch (Exception e) {
throw new RuntimeException(e);
//如果出现了异常,将默认值
//return value;
}
}
|
修改service
public class StaffServiceImpl implements StaffService {
.....
@Override
public CrmStaff login(CrmStaff staff) {
// MD5加密 密码
String logginPwd = MyStringUtils.getMD5Value(staff.getLoginPwd());
return staffDao.find(staff.getLoginName(), logginPwd);
}
|
3 UIAction
<!-- 2.1 配置公共 jsp访问 action
版本1:通过自定义action实现
<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>
版本3:通配符
result.name 默认值:success
uiAction_*_*
第一个星匹配文件夹名称,通过{1}获取
第二个星匹配jsp文件名称,通过{2}获取
例如:
uiAction_frame_top
/WEB-INF/pages/frame/top.jsp
总结:
action.class 默认值:ActionSupport
action.method 默认值:execute
result.name 默认值:success
-->
<action name="uiAction_*_*">
<result>/WEB-INF/pages/{1}/{2}.jsp</result>
</action>
|
4 登录拦截器
实现类
![](https://img-blog.csdn.net/20170518213742253?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
struts配置
1.注册,将实现类配置给struts
2.使用
2.1 每一个action单独使用
2.2 将多个拦截器打包生成自定义栈,action使用栈
2.3 将自定义栈,把默认栈覆盖
功能:判断session作用域是否有用户信息,如果有放行,如果没有拦截。
4.1 实现类
public class LoginInterceptor extends MethodFilterInterceptor {
@Override
public String doIntercept(ActionInvocation invocation) throws Exception {
//判断session作用域是否有用户信息,如果有放行,如果没有拦截。
Object obj = ActionContext.getContext().getSession().get("loginStaff");
if(obj == null){
/**友好信息 start*/
// 1 获得当前运行action
Object action = invocation.getAction();
// 2 判断运行时是否是ActionSupport
if(action instanceof ActionSupport){
ActionSupport actionSupport = (ActionSupport) action;
actionSupport.addFieldError("", "请登录");
}
/**友好信息 end*/
// 没有登录,需要登录
return "login";
}
//登录,放行
return invocation.invoke();
}
}
|
4.2 配置
<!-- 2.2 拦截器配置
* 先声明
方法1:每一个action单独使用,需要多次引用,否则默认将被覆盖
<action name="">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="loginInterceptor"></interceptor-ref>
</action>
方法2:将多个拦截器打包生成自定义栈,action使用栈
* 自定义拦截器栈
<interceptor-stack name="loginStack">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="loginInterceptor"></interceptor-ref>
</interceptor-stack>
* action引用
<action name="">
<interceptor-ref name="loginStack"></interceptor-ref>
</action>
方法3:将自定义栈,把默认栈覆盖
<default-interceptor-ref name="loginStack"></default-interceptor-ref>
-->
<interceptors>
<!-- @1)声明(注册) -->
<interceptor name="loginInterceptor" class="com.itheima.crm.web.interceptor.LoginInterceptor"></interceptor>
<!-- @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>
<!-- @3)声明默认 -->
<default-interceptor-ref name="loginStack"></default-interceptor-ref>
<!-- @4)全局结果集 -->
<global-results>
<result name="login">/WEB-INF/pages/login.jsp</result>
</global-results>
|
5 查询所有员工
dao层:findAll
service层:findAllStaff()
action类:findAll() --> staffAction_findAll
jsp页面:显示数据
5.1 dao层
@Override
public List<CrmStaff> findAll() {
return this.getHibernateTemplate().find("from CrmStaff");
}
|
5.2 service层
@Override
public List<CrmStaff> findAllStaff() {
return this.staffDao.findAll();
}
|
5.3 jsp入口
/ee19_crm/WebRoot/WEB-INF/pages/frame/left.jsp
![]()
5.4 action类
/**
* 查询所有
* @return
*/
public String findAll(){
// 1查询所有
List<CrmStaff> allStaff = staffService.findAllStaff();
// 2 将结果存放到值栈,方便jsp获得数据
// * 方式1:context (map)存放 put(key ,value) ,jsp页面获得 “#key” 。
// ActionContext.getContext().put(key, value)
// * 方式2:root (值栈) ,push(obj) ,一般数据为JavaBean 或 Map ,jsp页面获得“属性名” 或“key” 。
// ActionContext.getContext().getValueStack().push(o)
// * 方式3:root (值栈) ,set(key ,value) ,一般数据为List ,jsp页面获得“key”
// set() 底层 new Map(key,value) ,将 push(map )
// 使用 context存放数据
ActionContext.getContext().put("allStaff", allStaff);
return "findAll";
}
|
5.5 jsp展示
/ee19_crm/WebRoot/WEB-INF/pages/staff/listStaff.jsp
![](https://img-blog.csdn.net/20170518213948709?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbTBfMzc4NjI4Mjk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
5.6 web.xml 配置过滤器
注意:必须配置在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>
|
这是这个项目的开始写的不怎么好大家勿怪,后面我会继续更新把这个项目完成并把做项目的步骤写到这里,望大家点赞支持,有错误不好的地方大家及时提出,代码,jar需要的可以私密博主。今天就到这里了。