CRM系统
注册
bean包下 建用户类 User.java 提供set/get/tostring方法
private Long user_id;//用户id
private String user_code; //用户账号
private String user_name; //用户昵称
private String user_password;//用户密码
private char user_state; //用户状态 : 1 : 可用 ,0 : 暂停使用
User.hbm.xml 关联会生成 sys_user表
<hibernate-mapping>
<class name="com.itheima.bean.User" table="sys_user">
<id name="user_id">
<generator class="native"></generator>
</id>
<property name="user_code"/>
<property name="user_name"/>
<property name="user_password"/>
<property name="user_state"/>
</class>
</hibernate-mapping>
register.jsp 的前端请求
<form action="${pageContext.request.contextPath }/user_register" method="post">
用户名: <input type="text" name="user_code"/><br>
用户密码: <input type="password" name="user_password"/><br>
用户昵称: <input type="text" name="user_name"/><br>
input type="submit" value="注册"/></form>
UserAction.java 新建在 web.action包下
public class UserAction extends ActionSupport implements ModelDriven<User> {
private User user;//声明user对象
@Override
public User getModel() {//重写getModel方法new出user对象并返回
if (user==null) {
user = new User(); }
return user; }
private UserService userService;//声明userService对象
public void setUserService(UserService userService) {//提供set方法
this.userService = userService;}
public String register() {//注册
user.setUser_state('1');//设置状态为1
userService.register(user);//到userService 注册业务
return NONE;}//返回 为无
接口UserService
public interface UserService { void register(User user);}
UserService接口 实现类UserServiceImpl 并开启事务@Transactional
@Transactional
public class UserServiceImpl implements UserService {
private UserDao userDao;//声明userDao接口
public void setUserDao(UserDao userDao) {//提供set方法
this.userDao = userDao; }
@Override
public void register(User user) {//重写接口UserService 方法
String pwd = Md5Util.encodePwd(user.getUser_password());//把密码 加密
user.setUser_password(pwd);//设置封闭进去
userDao.save(user); }//调用userDao接口的.save方法
接口UserDao
public interface UserDao {void save(User user);}
UserDao接口 实现类UserDaoImpl extends HibernateDaoSupport
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
@Override
public void save(User user) {//重写接口方法
getHibernateTemplate().save(user);}}//继承getHibernateTemplate父类的save方法把user扔进去就好
applicationContext.xml
<!-- 以下属于UserAction模块配置 多例 -->
<bean id="userAction" class="com.it.web.action.UserAction" scope="prototype">
<property name="userService" ref="userService"></property>
</bean>
<bean id="userService" class="com.it.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.it.dao.impl.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
struts.xml配置:前端的请求以user_*开头的请求会到这里 然后指定一组请求集合package名user里的请求的Aiton类全限定名地址 result设置处理后的请求转发地址
<struts>
<package name="user" namespace="/" extends="struts-default">
<action name="user_*" class="userAction" method="{1}" ></action>
</package>
</struts>
登陆
前端 login.jsp
<FORM id=form1 name=form1 action="${pageContext.request.contextPath}/user_login" method="post">
UserAction.java里新建 login登陆方法
public String login() {//登陆
User loginUser=userService.login(user);//调登陆业务返回loginUser
if (loginUser!=null) {//登陆成功 存到session
ServletActionContext.getRequest().getSession().setAttribute("user", loginUser);
return Constant.LOGIN_SUCCESS;//返回到常量接口里的常量 常量再赋值给login_success
}
//ActionContext.getContext().getValueStack().set("msg", "帐号或密码错误");//存到值栈
addFieldError("msg", "帐号或密码错误");//采用struts里的方法回显错误 取值${fieldErrors.msg[0] }
return Constant.LOGIN_ERROR;}//返回 失败
interface UserService接:User login(User user); UserServiceImpl实现类:
public User login(User user) {
String pwd = Md5Util.encodePwd(user.getUser_password());//也把密码加密
user.setUser_password(pwd);//设置封闭进去
return userDao.findUser(user);
interface UserDao接口:User findUser(User user); UserDaoImpl实现类
public User findUser(User user) {
String hql="from User where user_code=? and user_password=? and user_state=1";
List<User> list = (List<User>) getHibernateTemplate().find(hql, user.getUser_code(),user.getUser_password());//spring里的模板方法得到的是list
if (list.size()>0) {
return list.get(0);//返回list里面的user 对象
}
return null;}
index.jsp框架结构
<FRAMESET frameSpacing=0 rows=80,* frameBorder=0> <!-- 框架划分上下 上面划分80像素下面占剩下所有 -->
<FRAME name=top src="top.jsp" frameBorder=0 noResize scrolling=no><!-- 上面放的内容 -->
<FRAMESET frameSpacing=0 frameBorder=0 cols=220,*><!-- 下面再放个框架 再划分左右 左占220像素右占剩下所有 -->
<FRAME name=menu src="${pageContext.request.contextPath}/menu.jsp" frameBorder=0 noResize><!-- 左边 -->
<FRAME name=main src="${pageContext.request.contextPath}/welcome.htm" frameBorder=0><!-- 右边 -->
</FRAMESET>
struts.xml
<package name="user" namespace="/" extends="struts-default">
<action name="user_*" class="userAction" method="{1}">
<result name="login_success" type="redirect">/index.jsp</result>
<result name="login_error">/login.jsp</result>
</action>
</package>
成功 就返回index.jsp 里框架里的top.jsp里展示昵称: 当前用户:${user.user_name }
方式重定向type=“redirect”
在top.jsp上面显示登陆的昵称
<tr><td height=35 align="right">当前用户:${user.user_name } <a href="#" >修改密码...
失败就返回login.jsp 在登陆名后面显示错误信息 struts里的方法回显 ${fieldErrors.msg[0] }
客户管理–新增客户/customer
index.jsp是个框架用<frameset>代替 <body> 左边是menu.jsp 增加客户
<A class=style2 href="${pageContext.request.contextPath}/jsp/customer/add.jsp" target=main>- 新增客户</A>
点击增加客户链接后 在框架的右边就显示add.jsp 里是个表单
<FORM id=form1 name=form1 action="${pageContext.request.contextPath }/customer_save" method=post>
bean包里 Customer 新增 客户类 都提供get/set/tostring方法
private Long cust_id;//客户id
private String cust_name;//客户名称
/*private String cust_source;
private String cust_industry;
private String cust_level;*/
//表示这个客户属于哪一种来源 用 字典对象
private BaseDict cust_source;//信息来源来源
private BaseDict cust_industry;//所属行业
private BaseDict cust_level;//客户级别
private String cust_phone;//移动电话
private String cust_address;//联系地址
private String cust_user_id;//负责人
private String cust_create_id;//创建人
Customer.hbm.xml 生成cst_customer客户表 客户和字典的关系是: 多对一
<hibernate-mapping>
<class name="com.it.bean.Customer" table="cst_customer">
<id name="cust_id">
<generator class="native"></generator>
</id>
<property name="cust_name"/>
<property name="cust_phone"/>
<property name="cust_address"/>
<property name="cust_user_id"/>
<property name="cust_create_id"/>
<!-- 这里要体现客户和字典的关系了,客户和字典的关系是: 多对一 -->
<many-to-one name="cust_source" class="com.it.bean.BaseDict"/>
<many-to-one name="cust_industry" class="com.it.bean.BaseDict"/>
<many-to-one name="cust_level" class="com.it.bean.BaseDict"/>
</class>
</hibernate-mapping>
跑起来就会自动建表了
CustomerAction 客户的action
public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {
private Customer customer;//声明customer/客户 对象
@Override
public Customer getModel() {//返回客户对象
if (customer==null) {
customer = new Customer();
}
return customer; }
private CustomerService customerService;//声明接口
public void setCustomerService(CustomerService customerService) {//提供set方法
this.customerService = customerService; }
public String save() {//新增保存客户业务
customerService.save(customer);
return NONE; }}
interface CustomerServic 接口 void save(Customer customer); 实现类CustomerServiceImpl
public class CustomerServiceImpl implements CustomerService {
private CustomerDao customerDao;//声明dao接口
@Override
public void save(Customer customer) {
customerDao.save(customer);//方法
}
interface CustomerDao接口 void save(Customer customer);实现类CustomerDaoImpl
public class CustomerDaoImpl extends HibernateDaoSupport implements CustomerDao {
@Override
public void save(Customer customer) {
getHibernateTemplate().save(customer); }//使用父类 模板方法保存客户
acclicationContext.xml
<!-- 以下属于客户模块 -->
<bean id="customerAction" class="com.it.web.action.CustomerAction" scope="prototype">
<property name="customerService" ref="customerService"></property>
</bean>
<bean id="customerService" class="com.it.service.impl.CustomerServiceImpl">
<property name="customerDao" ref="customerDao"></property>
</bean>
<bean id="customerDao" class="com.it.dao.impl.CustomerDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
struts
<!-- 以下属于客户模块 -->
<package name="customer" namespace="/" extends="struts-default">
<action name="customer_*" class="customerAction" method="{1}">
</action>
</package>
客户来源 客户行业 客户级别的三个下拉业务 字典bean
BaseDict 数据字典类 规范来源 bean包下 用于规范数据来源
private String dict_id; //下拉 主键
private String dict_type_code; //下拉 类型的代号 001所属行业/002来源
private String dict_type_name;//类型 名称
private String dict_item_name;// 来源行业级别 三个项目的名称
private String dict_item_code;//来源行业级别 三个项目的 项目
private int dict_sort;//排序字段
private char dict_enable;//是否停用 1使用
private String dict_memo;//备注
前端请求 是js请求
<script type="text/javascript">
function loadDict(type_code , tagId){
//发起请求,获取字典数据 按类型查询字典数据
var url = "${pageContext.request.contextPath }/baseDict_findByType";
$.post(url , {"dict_type_code" :type_code } , function(result){
//result -- list<BaseDict> -- json
$(result).each(function(i , n){ //i : 遍历的下标, n : 遍历出来的对象 字典对象
//var a = 3;
//找到标签,然后追加内容 val(aa) , text(aa) , html(xxx) , append(xxx)
$(tagId).append("<option value='"+n.dict_id+"'>"+n.dict_item_name+"</option>")
});
} , "json");
}
$(function(){
loadDict("001" , "#cust_industry"); //001 -- 客户行业
loadDict("002" , "#cust_source"); //002 -- 客户来源
loadDict("006" , "#cust_level");//006 -- 客户级别
})
</script>
BaseDictAction 的action 里面的 查询下拉业务
public class BaseDictAction extends ActionSupport {
private String dict_type_code;//声明 下拉类型的代号 001所属行业
public void setDict_type_code(String dict_type_code) {//提供set方法
this.dict_type_code = dict_type_code; }
private BaseDictService baseDictService;//声明接口
public void setBaseDictService(BaseDictService baseDictService) {
this.baseDictService = baseDictService;}//返回接口
public String findByType(){//查询下拉的 业务
try {
List<BaseDict> list = baseDictService.findByType(dict_type_code);//1. 查询数据
String json = new Gson().toJson(list);//2. list --> json
HttpServletResponse response = ServletActionContext.getResponse();//3. 写给页面。
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(json);
} catch (IOException e) {
e.printStackTrace();
}
return NONE;}
使用Struts方式返回json数据 /下拉业务的 信息来源 行业 级别
BaseDictAction 的action 里面的 查询下拉业务
public class BaseDictAction extends ActionSupport {
private String dict_type_code;//声明 下拉类型的代号 001所属行业
public void setDict_type_code(String dict_type_code) {//提供set方法
this.dict_type_code = dict_type_code; }
private BaseDictService baseDictService;//声明接口
public void setBaseDictService(BaseDictService baseDictService) {
this.baseDictService = baseDictService;}//返回接口
private List<BaseDict>list;//字典集合 变量
public List<BaseDict> getList() {//提供get方法
return list; }
//改成struts方式返回json数据 直接在struts里配置跳转成json类型
public String findByType(){
list = baseDictService.findByType(dict_type_code);//1. 查询数据业务
return Constant.JSON_SUCCESS;}//直接返回 常量 String JSON_SUCCESS = "json_success";
struts.xml root为固定写法把list跳转成json类型 extends=“json-default
<!-- 以下属于字典模块 -->
<package name="baseDict" namespace="/" extends="json-default">
<action name="baseDict_*" class="baseDictAction" method="{1}">
<result name="json_success" type="json">
<param name="root">list</param><!-- root为固定写法把list跳转成json类型 -->
</result>
</action>
</package>
这时候点提交会报错 直接返回会生成一条空的客户http://localhost/crm28_511/customer_save
要在add.jsp 里把三个下拉的 改成字典里的dict_id <select name=“cust_industry.dict_id 就可以了
数据校验
可以在前端做js校验 也可以在后台做校验 CustomerAction.java里的添加客户 save方法前对所有数据作校验
public String save(){
//在提交前对所有数据都进行校验 是springframework.util.StringUtils包提供的工具类;
if (StringUtils.isEmpty(customer.getCust_name())) {
addActionError("客户名称不能为空");//错误提示
return Constant.INPUT_ERROR;
}
if (StringUtils.isEmpty(customer.getCust_address())) {
addActionError("客户地址不能为空");//错误提示的值栈
return Constant.INPUT_ERROR;
}
..电话
}
if (StringUtils.isEmpty(customer.getCust_industry().getDict_id())) {
addActionError("客户行业没选");//错误提示
return Constant.INPUT_ERROR;
}..来源 级别
struts.xml 请求转发回来显示
<!-- 以下属于客户模块 -->
<package name="customer" namespace="/" extends="struts-default">
<action name="customer_*" class="customerAction" method="{1}">
<result name="input_error">/jsp/customer/add.jsp</result>
</action>
</package>
add.jsp
<%@ taglib uri="/struts-tags” prefix=“s” %>
在结果 后面加一列 里面显示值栈 <td>${actionErrors[0] }<td>
回显 漏掉的数据 不会重复
文本框回显 : 把 <input 换成<s:textfield 并属性值都要打双引号
<s:textfield class="textbox" id="sChannel2" style="WIDTH: 180px" maxLength="50" name="cust_address" />
布局乱了:原理是struts标签的默认主题是xhtml 生成的html标签是使用表格来布局 改一个struts.xml常量主题设成simple
<struts> <constant name="struts.ui.theme" value="simple"></constant>
下拉框回显: 1要知道提交上去是什么数据 2 提交上去的是value=2 然后用2去selectj里挨个问 并设置为selected就好
<script type="text/javascript">
$(function(){//加载完就 执行三个方法 下拉
loadDict("001" , "#cust_industry" , "${cust_industry.dict_id}"); //001 -- 客户行业
loadDict("002" , "#cust_source" , "${cust_source.dict_id}"); //002 -- 客户来源
loadDict("006" , "#cust_level" , "${cust_level.dict_id}");//006 -- 客户级别
})
function loadDict(type_code , tagId , oldVal){//传旧的值进来回显
//发起请求,获取字典数据 按类型查询字典数据
var url = "${pageContext.request.contextPath }/baseDict_findByType";
$.post(url , {"dict_type_code" :type_code } , function(result){
$(result).each(function(i , n){ //i : 遍历的下标, n : 遍历出来的对象 字典对象
$(tagId).append("<option value='"+n.dict_id+"'>"+n.dict_item_name+"</option>")
});
//选中该选中的option 在指定的id标签身上找option标签, 按照value值来找,如果找到了就修改这个option标签的属性,修改selected属性,值为selected
$(tagId).find("option[value='"+oldVal+"']").attr("selected","selected");
} , "json"); }
</script>
图片上传
add.jsp 在联系电话后加一个 文件上传标签file
<tr><td>客户资质 :</td>
<td>
<input type="file" name="upload"/>
</td></tr>
并在表单下面写
<!-- enctype="application/x-www-form-urlencoded" : 表示提交上去的是一份经过url编码的form表单数据,主要针对文本数据 enctype="multipart/form-data" : 提交上来的是表单数据,包含多份, 有表单数据也有文件数据 -->
<FORM id=form1 name=form1 action="${pageContext.request.contextPath }/customer_save" method=post
enctype="multipart/form-data">
CustomerAction 的save()方法里处理 先声明对象
//struts获取文件数据 需要声明文件对象和以下三个并提供set方法
private File upload;//File对象 java.io.File 值是file标签的name属性值
private String uploadContextType;//文件类型 name属性值+ContextType固定写法
private String uploadFileName;//文件名称 name属性值+FileName固定写法
public void setUpload(File upload) {
this.upload = upload; }
public void setUploadContextType(String uploadContextType) {
this.uploadContextType = uploadContextType; }
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName; }
public String save() throws IOException{
//存储文件数据把tem转成jpg|png
File file=new File("d://hm28", MyFileUtil.getFileName(uploadFileName));//文件对象 文件名拼接为要存的路径+工具类静态方法生成的随机名
FileUtils.copyFile(upload, file);//用org.apache.commons.io 原文件选属性值 和目标文件
上传限制 在struts.xml里 设置为200m
<constant name="struts.multipart.maxSize" value="209715200"></constant>
客户列表
menu.jsp 左框 里客户列表请求
<tr>
<td class=menuSmall>
<a class=style2 href="${pageContext.request.contextPath}/customer_findByPage.action" target=main>- 客户列表</a>
</td>
</tr>
CustomerAction里的分页显示客户列表 public String findByPage() {
public String findByPage() {
//离线对象如果只是这么创建出来,背后的sql语句 select * from customer;
//只会使用离线对象的两个方法 setXXX(针对聚合查询 总记录数、最大值、最小值、) addXXX(针对where条件的设置)
DetachedCriteria criteria =DetachedCriteria.forClass(Customer.class);//离线对象 [dɪˈtætʃt] [kraɪˈtɪrɪə]
//2. 查询数据业务,有返回值
PageBean<Customer> pageBean = customerService.findByPage(criteria , currentPage , pageSize);
ActionContext.getContext().getValueStack().push(pageBean);//3. 把pageBean存储到作用域 值栈。 push | set | 属性
return Constant.PAGE_SUCCESS;}//返回
PageBean.java bean包下 提供set/get/tostring方法
public class PageBean<T> {
private int currentPage;//当前页码
private int totalPage;//总页数
private int pageSize;//每页条数
private int totalSize;//总条数
private List<T>list;//当前页集合
到 CustomerServiceImpl 分页显示客户列表 有两个地方会走这个方法:
@Transactional//注解业务
public class CustomerServiceImpl implements CustomerService {
..
private int currentPage=1;//先设置 默认第一页/当前页 提供set方法以便页面修改
private int pageSize=5;//设置每页条数 提供set方法以便页面修改获取具体条数
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;}
public String findByPage() {//分布查询客户列表 两个地方走这个方法左侧客户列表不带条件 筛选带条件
//离线对象如果只是这么创建出来,背后的sql语句 select * from customer;是QBC查询重要组件 能够在dao层之上两层进行查询条件封装 也可以不封装
//只会使用离线对象的两个方法 setXXX(针对聚合查询 总记录数、最大值、最小值、addXXX(针对where条件的设置)
DetachedCriteria criteria=DetachedCriteria.forClass(Customer.class);//离线对象
PageBean<Customer> pageBean = customerService.findByPage(criteria , currentPage , pageSize);//查询数据业务 返回pageBean 集合对象
ActionContext.getContext().getValueStack().push(pageBean);//3. 把pageBean存储到作用域 值栈。 push | set | 属性
return Constant.PAGE_SUCCESS;}//返回
service接口 CustomerService
public interface CustomerService {
PageBean<Customer> findByPage(DetachedCriteria criteria, int currentPage, int pageSize);
service实现类 CustomerServiceImpl
public PageBean<Customer> findByPage(DetachedCriteria criteria, int currentPage, int pageSize) {
int totalSize=customerDao.findCound(criteria);//查出总条数 传离线对象 区分筛选某一种类型数据
List<Customer>list=customerDao.findByPage(criteria,currentPage,pageSize);//查出PageBean的list
PageBean<Customer> pageBean = new PageBean<>();//new pageBean对象
pageBean.setCurrentPage(currentPage);//手动封装 当前页
int totalPage=totalSize%pageSize==0?totalSize/pageSize:(totalSize/pageSize)+1;//三元计算出总页数 整除就总页除每页条数,不整除加1
//int totalPage=(int)Math.ceil(totalSize*1.0/pageSize);//也可以用工具类向上取整只要有小数点就向上取成整数
pageBean.setTotalPage(totalPage);//手动封装 总页数
pageBean.setPageSize(pageSize);//手动封装 每页条数
pageBean.setTotalSize(totalSize);//手动封装 总条数
pageBean.setList(list);//手动封装pageBean
return pageBean;}//返回的是pageBean
dao接口 CustomerDao
public interface CustomerDao {
int findCound(DetachedCriteria criteria);
List<Customer> findByPage(DetachedCriteria criteria, int currentPage, int pageSize);
dao实现 CustomerDaoImpl
@Override//查询客户总条数 用hibernate模板查
public int findCound(DetachedCriteria criteria) {
criteria.setProjection(Projections.rowCount());//离线对象经过这个语句就变成查select count(*) from customer查行个数 默认是查全部select*from customer
List<Long> list = (List<Long>) getHibernateTemplate().findByCriteria(criteria);
if (list.size()>0) {
return list.get(0).intValue();//如果集合中有条数 就转成int
}
return 0; }
@Override//查分页
public List<Customer> findByPage(DetachedCriteria criteria, int currentPage, int pageSize) {
criteria.setProjection(null);//离线对象 重置回来select*from customer
return (List<Customer>) getHibernateTemplate().findByCriteria(criteria, (currentPage-1)*pageSize, pageSize); }//查分页 离线对象 当前页减1再乘每页条数 每页条数
struts.xml
<!-- 以下属于客户模块 -->
<package name="customer" namespace="/" extends="struts-default">
<action name="customer_*" class="customerAction" method="{1}">
<result name="page_success">/jsp/customer/list.jsp</result>
/jsp/customer/list.jsp
<%@ taglib uri="/struts-tags” prefix=“s” %>
<!-- 遍历存在值栈中的list 的每一条客户信息 并展示各项信息 -->
<c:forEach items="${list }" var="customer">
<TR style="FONT-WEIGHT: normal; FONT-STYLE: normal; BACKGROUND-COLOR: white; TEXT-DECORATION: none">
<TD>${customer.cust_name }</TD>
<TD>${customer.cust_level.dict_item_name}</TD><!-- 是取得级别里面的名字要.字典 -->
<TD>${customer.cust_source.dict_item_name }</TD>
<TD>${customer.cust_industry.dict_item_name }</TD>
<TD>${customer.cust_address }</TD>
<TD>${customer.cust_phone }</TD>
<TD>
<a href="${pageContext.request.contextPath }/customer/CustomerServlet?method=editCustomerUI&custId=${customer.cust_id}">修改</a>
<a href="${pageContext.request.contextPath }/customer/CustomerServlet?method=removeCustomer&custId=${customer.cust_id}">删除</a>
</TD>
</TR>
</c:forEach>
懒加载过滤器 web.xml
<!-- 过滤器 懒加载 搜OpenSessionInViewFilter第5版 再在前端请求方法后加 .action -->
<filter>
<filter-name>openSession</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSession</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
遍历客户 下面的分页 上下页 分页 跳转的div
<DIV style="LINE-HEIGHT: 20px; HEIGHT: 20px; TEXT-ALIGN: right">
共[<B>${totalSize}</B>]条信息,按每页显示
<select name="pageSize" onchange="changePageSize()"><!-- 点击改变就执行JS方法 -->
<option value="5" <c:if test="${pageSize==5 }">selected</c:if>>5</option>
<option value="10" <c:if test="${pageSize==10 }">selected</c:if>>10</option>
<option value="15" <c:if test="${pageSize==15 }">selected</c:if>>15</option>
<option value="20" <c:if test="${pageSize==20 }">selected</c:if>>20</option>
</select>
条,共[<B>${totalPage}</B>]页 <B>当前第${currentPage}页</B>
[
<s:if test="currentPage==1"><!-- 如果是第一页就是第一页文字不可点击 -->
第一页
</s:if>
<s:else>
<A href="javascript:to_page(${currentPage-1})">到前一页</A><!-- 点击执行js方法 -->
</s:else>
][
<s:if test="currentPage==totalPage"><!-- 如果是总页数就是最后一页文字不可点击 -->
最后一页
</s:if>
<s:else>
<A href="javascript:to_page(${currentPage+1})">到后一页</A>
</s:else>
]
<input type="button" value="跳转到第" onclick="to_page()"/>
<input type="text" size="3" id="page" name="currentPage" />
页
</DIV>
js
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.11.3.min.js"></script>
<SCRIPT language=javascript>
function to_page(page){//to_page方法传page参数 如果有参数就改变并提交表单 js版本是1.11.3
if(page){//如果有参数就执行改变#page标签的页数
$("#page").val(page);
}else{//点击转转到 就进入else分支
var requestPage=$("#page").val();//当前输入的值
var totalPage="${totalPage}";//总页数
if (Number(requestPage)>Number(totalPage)) {//如果输入值大于总页 就转到最后一页
alert("输入的第"+requestPage+"页,超过最大"+totalPage+"页,现到最后一页");
$("#page").val(totalPage); } }
document.customerForm.submit();}//并提交整个表单到 customer_findByPage.action
function changePageSize(){//改变每页显示条数 的方法
document.customerForm.submit(); //提交整个表单到findByPage.action
}
</SCRIPT>
最后都是提交的表单
<FORM id="customerForm" name="customerForm" action="${pageContext.request.contextPath }/customer_findByPage.action" method=post>
筛选
list.jsp
<TABLE cellSpacing=0 cellPadding=2 border=0>
<TBODY>
<TR>
<TD>客户名称:</TD>
<TD><s:textfield class="textbox" id="sChannel2" style="WIDTH: 80px" maxLength="50" name="cust_name" /></TD>
<TD>客户来源:</TD>
<td>
<select name="cust_source.dict_id" class=textbox id="cust_source" style="WIDTH: 100px;height:21px">
<option value="">---请选择---</option>
</select>
</td>
<TD>客户行业:</TD>
<td>
<select name="cust_industry.dict_id" class=textbox id="cust_industry" style="WIDTH: 100px;height:21px">
<option value="">---请选择---</option>
</select>
</td>
<TD>客户级别:</TD>
<td>
<select name="cust_level.dict_id" class=textbox id="cust_level" style="WIDTH: 100px;height:21px">
<option value="">---请选择---</option>
</select>
</td>
<TD>客户电话:</TD>
<TD><s:textfield class="textbox" id="sChannel2" style="WIDTH: 80px" maxLength="50" name="cust_phone" /></TD>
<TD><INPUT class=button id=sButton2 type=submit value=" 筛选 " name=sButton2></TD><!-- 点击按钮就提交 -->
</TR>
</TBODY>
</TABLE>
CustomerAction.java
校验有没有带筛选条件就先用qbc查询出来再分页
public String findByPage() {//分布查询客户列表 两个地方走这个方法左侧客户列表不带条件 筛选带条件
//离线对象如果只是这么创建出来,背后的sql语句 select * from customer;是QBC查询重要组件 能够在dao层之上两层进行查询条件封装 也可以不封装
//只会使用离线对象的两个方法 setXXX(针对聚合查询 总记录数、最大值、最小值、addXXX(针对where条件的设置)
DetachedCriteria criteria=DetachedCriteria.forClass(Customer.class);//离线对象
//判断条件 走筛选的如果带上了条件 就把查询语句 先带上参数查询
if (!StringUtils.isEmpty(customer.getCust_name())) {//校验客户名称 用工具比较客户里名字不为空 就代表前端表单属性name 用模型驱动 传文本框和选择框参数过来了
criteria.add(Restrictions.like("cust_name", "%"+customer.getCust_name()+"%"));}//qbc查询 模糊查询模型驱动获得前端的cust_name作为条件和数据库里查询
if (!StringUtils.isEmpty(customer.getCust_phone())) {//校验客户电话 qbc要加% List list = criteria.add(Restrictions.like("pname", "%肉%")).list();
criteria.add(Restrictions.like("cust_phone", "%"+customer.getCust_phone()+"%"));}
if (customer.getCust_source()!=null&&!StringUtils.isEmpty(customer.getCust_source().getDict_id())) {//校验客户来源里的来源对象不为空并且 里面传过来参数的id值不为空
criteria.add(Restrictions.eq("cust_source.dict_id", customer.getCust_source().getDict_id()));}//就把参数进去 以id查询
if (customer.getCust_industry()!=null&&!StringUtils.isEmpty(customer.getCust_industry().getDict_id())) {//校验客户行业里的id值
criteria.add(Restrictions.eq("cust_industry.dict_id", customer.getCust_industry().getDict_id()));}
if (customer.getCust_level()!=null&&!StringUtils.isEmpty(customer.getCust_level().getDict_id())) {//校验客户级别里的id值
criteria.add(Restrictions.eq("cust_level.dict_id", customer.getCust_level().getDict_id()));}
//并以分页查询
PageBean<Customer> pageBean = customerService.findByPage(criteria , currentPage , pageSize);//查询数据业务 返回pageBean对象
System.out.println(pageBean);
ActionContext.getContext().getValueStack().push(pageBean);//3. 把pageBean存储到作用域 值栈。 push | set | 属性
return Constant.PAGE_SUCCESS;}//返回
js 加载完就执行下拉三个方法
执行的js的 loadDict方法
function loadDict(type_code , tagId , oldVal){//传旧的值进来
<script type="text/javascript">
$(function(){//加载完就 执行三个方法 下拉
loadDict("001" , "#cust_industry" , "${cust_industry.dict_id}"); //001 -- 客户行业
loadDict("002" , "#cust_source" , "${cust_source.dict_id}"); //002 -- 客户来源
loadDict("006" , "#cust_level" , "${cust_level.dict_id}");//006 -- 客户级别
})
function loadDict(type_code , tagId , oldVal){//传旧的值进来回显
//发起请求,获取字典数据 按类型查询字典数据
var url = "${pageContext.request.contextPath }/baseDict_findByType";
$.post(url , {"dict_type_code" :type_code } , function(result){
$(result).each(function(i , n){ //i : 遍历的下标, n : 遍历出来的对象 字典对象
$(tagId).append("<option value='"+n.dict_id+"'>"+n.dict_item_name+"</option>")
});
//选中该选中的option 在指定的id标签身上找option标签, 按照value值来找,如果找到了就修改这个option标签的属性,修改selected属性,值为selected
$(tagId).find("option[value='"+oldVal+"']").attr("selected","selected");
} , "json"); }
</script>
回显筛选的文本框用标记 下拉用上面的js
文本框回显 : 把 <input 换成<s:textfield 并属性值都要打双引号
<TD>客户名称:</TD>
<TD><s:textfield class="textbox" id="sChannel2" style="WIDTH: 80px" maxLength="50" name="cust_name" /></TD>
<TD>客户电话:</TD>
<TD><s:textfield class="textbox" id="sChannel2" style="WIDTH: 80px" maxLength="50" name="cust_phone" /></TD>
信息创建人和对客户负责人
list.jsp 里添加
<TD>信息创建人</TD>
<TD>对客户负责人</TD>
<TD>操作</TD> <!--操作的上面添加-->
<!--遍历的地方添加 并显示 -->
<TD>${customer.cust_create_id.user_name }</TD><TD>${customer.cust_user_id.user_name }</TD>
CustomerAction 里的 添加客户方法save 前先设置创建人
//设置信息创建人和客户负责人 谁负责添加的这个客户谁就是创建人和负责人
User user = (User) ServletActionContext.getRequest().getSession().getAttribute("user");//取到登陆的user
customer.setCust_create_id(user);//设置客户的创建人
customer.setCust_user_id(user);//设置对客户负责人的名字 为登陆创建的user对象
customerService.save(customer);return NONE;
bean包 Customer.java 创建人/负责人String更改为对象user
private User cust_create_id;//信息创建人 改成对象类型 xml也要改
private User cust_user_id; //对客户负责人
Customer.hbm.xml映射关系更改
<!-- <property name="cust_user_id"/>
<property name="cust_create_id"/> 删除其它字段和持久化类关系 改成多对一的关系 客户和用户-->
<many-to-one name="cust_create_id" class="com.itheima.bean.User"></many-to-one>
<many-to-one name="cust_user_id" class="com.itheima.bean.User"></many-to-one>
添加客户提交保存 并重定向到分页查询方法
return Constant.SAVA_SUCCESS;
struts.xml 重定向到分页查询方法
jsp的请求转发(默认)dispatcher 重定向redirect
action的请求转发(默认)chain重定向redirectAction
<result name="save_success" type="redirectAction">customer_findByPage</result>
删除
list.jsp 链接到执行js代码 传id过去
<a href="javascript:del(${customer.cust_id})">删除</a>
js 到delete方法传id过去
function del(id){//删除方法
var flag=confirm("确定删除这个客户吗");
if (flag) {//确定就跳转
location.href="${pageContext.request.contextPath }/customer_delete?cust_id="+id; } }
CustomerAction.java建delete方法
public String delete() {//删除客户的方法 传对象
customerService.delete(customer);
return Constant.DELETE_SUCCESS;}
CustomerService接口void delete(Customer customer);
CustomerServiceImpl public void delete(Customer customer) {
customerDao.delete(customer);}
CustomerDao接口 void delete(Customer customer);
CustomerDaoImpl实现public void delete(Customer customer) {getHibernateTemplate().delete(customer); }
struts.xml 重定向到方法
<result name="delete_success" type="redirectAction">customer_findByPage</result>
修改
list.jsp 传参数过去到edit方法
<a href="${pageContext.request.contextPath }/customer_edit?cust_id=${customer.cust_id}">修改</a>
CustomerAction.java第一步先根据id查询客户对象存值栈 跳转到修改页面
private Customer editCustomer;//属性方法存值栈 声明findById查询出来客户的customer 的变量
public Customer getEditCustomer() {//提供get方法
return editCustomer;}
public String edit() {//修改客户的方法 第一步先根据id查询客户对象数据跳转到修改页面
editCustomer = customerService.findById(customer.getCust_id());
//以属性方法存值栈 把editCustomer成全局变量提供get方法就存到值栈了
return Constant.EDIT_SUCCESS;}//跳转
CustomerService接口Customer findById(Long cust_id);
CustomerServiceImpl public Customer findById(Long cust_id) {return customerDao.findById(cust_id);}
CustomerDao接口 Customer findById(Long cust_id);
CustomerDaoImpl实现public Customer findById(Long cust_id) { return getHibernateTemplate().get(Customer.class, cust_id);}
struts.xml 转到edit页面
<result name="edit_success">/jsp/customer/edit.jsp</result>
关闭懒加载才能进入edit.jsp Customer.hbm.xml
<many-to-one lazy="false" name="cust_create_id" class="com.itheima.bean.User"></many-to-one>
<many-to-one lazy="false" name="cust_user_id" class="com.itheima.bean.User"></many-to-one>
<many-to-one lazy="false" name="cust_source" class="com.itheima.bean.BaseDict"/>
<many-to-one lazy="false" name="cust_industry" class="com.itheima.bean.BaseDict"/>
<many-to-one lazy="false" name="cust_level" class="com.itheima.bean.BaseDict"/>
或者在请求的时候就带 .action
<a href="${pageContext.request.contextPath }/customer_edit.action?cust_id=${customer.cust_id}">修改</a>
回显到 edit.jsp 修改成 值栈里对应的value
<!-- 修改的id的隐藏域 -->
<input type="hidden" name="cust_id" value="${editCustomer.cust_id}">
<!-- 要修改表单项目也 修改成值栈里的 -->
<TABLE cellSpacing=0 cellPadding=5 border=0>
<TR>
<td>客户名称:</td>
<td>
<INPUT class=textbox id=sChannel2 style="WIDTH: 180px" maxLength=50 name="cust_name" value="${editCustomer.cust_name}">
</td>
<td>所属行业 :</td>
<td>
<select name="cust_industry.dict_id" class=textbox id="cust_industry" style="WIDTH: 180px;;height:21px">
<option value="non">---请选择---</option>
</select>
</td>
</TR>
<TR>
<td>信息来源 :</td>
<td>
<select name="cust_source.dict_id" class=textbox id="cust_source" style="WIDTH: 180px;;height:21px">
<option value="non">---请选择---</option>
</select>
</td>
<td>客户级别:</td>
<td>
<select name="cust_level.dict_id" class=textbox id="cust_level" style="WIDTH: 180px;;height:21px">
<option value="non">---请选择---</option>
</select>
</td>
</TR>
<TR>
<td>联系地址 :</td>
<td>
<INPUT class=textbox id=sChannel2 style="WIDTH: 180px" maxLength=50 name="cust_address" value="${editCustomer.cust_address}">
</td>
<td>联系电话 :</td>
<td>
<INPUT class=textbox id=sChannel2 style="WIDTH: 180px" maxLength=50 name="cust_phone" value="${editCustomer.cust_phone}">
</td>
</TR>
<tr>
<td rowspan=2>
<INPUT class=button id=sButton2 type=submit value=" 保存 " name=sButton2>
</td>
</tr>
</TABLE>
js 设置下拉的回显
<SCRIPT language=javascript>
$(function(){//加载完就 执行三个方法 下拉
loadDict("001" , "#cust_industry" , "${editCustomer.cust_industry.dict_id}"); //001 -- 客户行业
loadDict("002" , "#cust_source" , "${editCustomer.cust_source.dict_id}"); //002 -- 客户来源
loadDict("006" , "#cust_level" , "${editCustomer.cust_level.dict_id}");//006 -- 客户级别
})
function loadDict(type_code , tagId , oldVal){//传旧的值进来回显
//发起请求,获取字典数据 按类型查询字典数据
var url = "${pageContext.request.contextPath }/baseDict_findByType";
$.post(url , {"dict_type_code" :type_code } , function(result){
$(result).each(function(i , n){ //i : 遍历的下标, n : 遍历出来的对象 字典对象
$(tagId).append("<option value='"+n.dict_id+"'>"+n.dict_item_name+"</option>")
});
//选中该选中的option 在指定的id标签身上找option标签, 按照value值来找,如果找到了就修改这个option标签的属性,修改selected属性,值为selected
$(tagId).find("option[value='"+oldVal+"']").attr("selected","selected");
} , "json"); }
</SCRIPT>
保存
edit.jsp
<FORM id=form1 name=form1 action="${pageContext.request.contextPath }/customer_update" method=post>
CustomerAction建update方法
public String update() {//修改客户并保存的方法 修改客户第二步
customerService.update(customer);
return Constant.UPDATE_SUCCESS;}//跳转
CustomerService接口void update(Customer customer);
CustomerServiceImpl public void update(Customer customer) {
customerDao.update(customer);}
CustomerDao接口 void update(Customer customer);
CustomerDaoImpl实现public void update(Customer customer) {getHibernateTemplate().update(customer); }
struts.xml 重定向到方法
<result name="update_success" type="redirectAction">customer_findByPage</result>
信息创建人和对客户负责人被修改成空了 要在edit.jsp加两个隐藏域
<!-- 信息创建人和对客户负责人的隐藏域 value还是之前的 查出来要被修改对象里面的 对客户负责人里的用户帐号-->
<input type="hidden" name="cust_user_id.user_id" value="${editCustomer.cust_user_id.user_id}">
<input type="hidden" name="cust_create_id.user_id" value="${editCustomer.cust_create_id.user_id}">
客户图片回显
Customer.java bean包下的加一个图片字段 image 配置映射
private String cust_image;
Customer.hbm.xml<property name="cust_image"/>
edit.jsp 联系电话下面 添加位置显示图片
<tr>
<td>客户资质 :</td>
<td>
<img src="${pageContext.request.contextPath }/${editCustomer.cust_image}" />
<input type="file" value="">
</td>
</tr>
在增加客户保存之前 把图片地址设置进去
//存储图片
if(upload != null){
//存储文件 tmp---jpg | png
String fileName = MyFileUtil.getFileName(uploadFileName);
File file = new File("D:/heima28/img" , fileName);
FileUtils.copyFile(upload, file);
//数据库里存放地址设置
customer.setCust_image("img/"+fileName);
}
customerService.save(customer);
return Constant.SAVA_SUCCESS;
}
改tomcat配置文件 Servers里面 Tomcat v7.0 Server at localhost-config 配server.xml 真实路径和 项目名虚拟路径
<Context docBase="D:/heima28/img" path="/crm28_522/img"/>
联系人
客户拜访
客户拜访时间日期格式问题:
方式1 转发器utils +xwork-conversion.properties配置
方式2 标签库
BaseDao抽取
联系人和客户 LinkManDaoImpl和CustomerDaoImpl几乎一样
BaseDao.java
package com.itheima.dao;
import java.io.Serializable;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import com.itheima.bean.Customer;
public interface BaseDao<T> {
void save(T t);
void delete(T t);
void update(T t);
T findById(Serializable id);
List<T> findAll();
List<T> findByPage(DetachedCriteria criteria, int currentPage, int pageSize);
int findCount(DetachedCriteria criteria);
}
BaseDaoImpl.java
package com.itheima.dao.impl;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import com.itheima.dao.BaseDao;
public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> {
private Class clazz ;//声明
public BaseDaoImpl(){//有参构造 反射解析T类型
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
clazz = (Class) pt.getActualTypeArguments()[0];
}
@Override //查id
public T findById(Serializable id) {
return (T) getHibernateTemplate().get(clazz, id);
}
@Override //查全部
public List<T> findAll() {
return (List<T>) getHibernateTemplate().findByCriteria(DetachedCriteria.forClass(clazz));
}
//=================================================
@Override //增
public void save(T t) {
getHibernateTemplate().save(t);
}
@Override //删
public void delete(T t) {
getHibernateTemplate().delete(t);
}
@Override //改
public void update(T t) {
getHibernateTemplate().update(t);
}
@Override //查分页的List集合
public List<T> findByPage(DetachedCriteria criteria, int currentPage, int pageSize) {
System.out.println("使用leBaseDaoImpl的findByPage方法~!~");
criteria.setProjection(null);
return (List<T>) getHibernateTemplate().findByCriteria(criteria, (currentPage-1)*pageSize , pageSize);
}
@Override //查总条数
public int findCount(DetachedCriteria criteria) {
criteria.setProjection(Projections.rowCount());
List<Long> list = (List<Long>) getHibernateTemplate().findByCriteria(criteria);
if(list.size() > 0 ){
return list.get(0).intValue();
}
return 0;
}
}
CustomerDao.java 继承BaseDao
public interface CustomerDao extends BaseDao<Customer> {
CustomerDaoImpl.java继承BaseDaoImpl 实现接口CustomerDao
public class CustomerDaoImpl extends BaseDaoImpl<Customer> implements CustomerDao {
登陆拦截器
\itheima\web\interceptor\LoginInterceptor.java
public class LoginInterceptor extends MethodFilterInterceptor{
@Override
protected String doIntercept(ActionInvocation arg0) throws Exception {
User user = (User)ServletActionContext.getRequest().getSession().getAttribute("user");
if(user == null){
System.out.println("没有登录,现在要去执行登录");
return "login";
}
System.out.println("已经登录,放行");
return arg0.invoke();
}
struts.xml 在要拦截的package里声明拦截器
<package name="base" extends="json-default" namespace="/">
<!-- 1. 声明拦截器 -->
<interceptors>
<interceptor name="LoginInterceptor" class="com.itheima.web.interceptor.LoginInterceptor">
<!-- 不拦的 -->
<param name="excludeMethods">createCode,login</param>
</interceptor>
<!-- 2. -->
<interceptor-stack name="baseStack">
<interceptor-ref name="LoginInterceptor"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<!-- 2. 定义这个包,默认的拦截器是什么 -->
<default-interceptor-ref name="baseStack"/>
<!-- 3. 配置共性的result -->
<global-results>
<result name="login" type="redirect">/login.jsp</result>
</global-results>
</package>