crm系统,SSH框架实现
公网访问地址点我
项目源码:这几天查资料时遇到好多收费或者要积分的资源,烦死了,马上考研了,做点好事吧,放一份csdn要积分的,再放一份网盘下载。csdn也骗了200多积分了,还剩160,感觉没啥用了2333333333
积分下载
直接下载
网盘下载 提取码:433z
(注意上传路径写死了,客户列表的资质超链接地址也写死了,修改修改为自己主机上存在的路径,否则上传和查看上传功能不能呢个用 分别在uploadUtils.java和customer的list.jsp的资质处)
运行截图:
随便放两张吧:
下面放出所有源码,方便以后当文档查询
目录
目录结构
com.itheima.dao
BaseDao.java
BaseDaoImpl.java
CustomerDao.java
CustomerDaoImpl.java
DictDao.java
DictDaoImpl.java
LinkmanDao.java
LinkmanDaoImpl.java
UserDao.java
UserDaoImpl.java
VisitDao.java
VisitDaoImpl.java
com.itheima.domain
Customer.java
Dict.java
Linkman.java
PageBean.java
User.java
Visit.java
domainXml
Customer.hbm.xml
Dict.hbm.xml
Linkman.hbm.xml
User.hbm.xml
Visit.hbm.xml
com.itheima.service
CustomerService.java
CustomerServiceImpl.java
DictService.java
DictServiceImpl.java
LinkmanService.java
LinkmanServiceImpl.java
UserService.java
UserServiceImpl.java
VisitService.java
VisitServiceImpl.java
com.itheima.utils
FastJsonUtil.java
MD5Utils.java
UploadUtils.java
com.itheima.web.action
BaseAction.java
CustomerAction.java
DictAction.java
LinkmanAction.java
UserAction.java
VisitAction.java
com.itheima.web.interceptor
UserInterceptor.java
核心xml
applicationContext.xml
struts.xml
web.xml
log4j.properties
JSP
WebContent
index.jsp
login.jsp
regist.jsp
top.jsp
welcome.jsp
/jsp/customer
add.jsp0
edit.jsp0
list.jsp0
/jsp/linkman
add.jsp1
edit.jsp1
list.jsp1
/jsp/totals
sources.jsp
/jsp/visit
add.jsp3
list.jsp3
SQL
package com.itheima.dao;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import com.itheima.domain.PageBean;
/**
* 以后所有的dao接口都需要继承BaseDao 接口
*写成泛型形式,方便动态传入类型
*/
public interface BaseDao {
public void save(T t);
public void delete(T t);
public void update(T t);
public T findById(Long id);
public T findById(String id);//重载id
public List findAll();
public PageBean findByPage(Integer pageCode, Integer pageSize, DetachedCriteria criteria);
}
package com.itheima.dao;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import com.itheima.domain.Customer;
import com.itheima.domain.PageBean;
/**
* 以后所有的DaoImpl都可以继承BaseDaoImpl,那么通用增删改查和分页就可以直接用了
* @author 寒面银枪
* 2019年7月6日-下午2:31:22
*/
@SuppressWarnings("all") //忽略所有警告
public class BaseDaoImpl extends HibernateDaoSupport implements BaseDao {
//定义成员属性(为了拿到T的类型 T.class不行报错)
private Class clazz;
/*public BaseDaoImpl(Class clazz) {
this.clazz = clazz;//让子类来传类型 (重写子类无参构造器 daoimpl一般也不会有带参构造器 所以很安全了)
}//注意此类没有无参构造器了 子类必须自己重写无参构造器了(因为继承不到了)
能解决问题 但是很麻烦 每次都要重写无参构造器
*/
public BaseDaoImpl() {
//验证创建子类 父类构造器会自动执行,并且this指的是子类
//System.out.println("BaseDaoImpl执行了... "+this.getClass().getSimpleName());
//下面利用反射 一步一步拿到子类继承此父类时注入的泛型T
//1.拿到子类对象
Class c=this.getClass();
//2.获取到BaseDaoImpl
Type type = c.getGenericSuperclass();
//将type转换为另一个子类 即可获得泛型
if(type instanceof ParameterizedType) {//注意ParameterizedType是反射包里的
ParameterizedType ptype=(ParameterizedType) type;
//获取Customer
Type[] types = ptype.getActualTypeArguments();//之所以是数组 因为有的泛型有好多个类型 eg:Map
this.clazz=(Class) types[0];
}
}
/**
* 添加
*/
@Override
public void save(T t) {
this.getHibernateTemplate().save(t);
}
/**
* 删除
*/
@Override
public void delete(T t) {
this.getHibernateTemplate().delete(t);
}
/**
* 修改
*/
@Override
public void update(T t) {
this.getHibernateTemplate().update(t);
}
/**
* 通过主键查询
*/
@Override
public T findById(Long id) {
T t = (T) this.getHibernateTemplate().get(clazz, id);
return t;
}
/**
* 通过主键查询
*/
@Override
public T findById(String id) {
T t = (T) this.getHibernateTemplate().get(clazz, id);
return t;
}
/**
* 查询所有数据
*/
@Override
public List findAll() {
//此时HQL查询最方便 clazz.getSimpleName()拿到类型名
return (List) this.getHibernateTemplate().find("from "+clazz.getSimpleName());
}
/**
* 分页查询
*/
@Override
public PageBean findByPage(Integer pageCode, Integer pageSize, DetachedCriteria criteria) {
//创建分页的对象
PageBean page=new PageBean();
page.setPageCode(pageCode);
page.setPageSize(pageSize);
/*hibernate要么用HQL(Hibernate查询语句 要么用QBC 条件查询 好好看QBC条件查询 Hibernate_day04 列了5大类查询)*/
//总记录数
criteria.setProjection(Projections.rowCount());
List list = (List) this.getHibernateTemplate().findByCriteria(criteria);
if(list!=null && list.size()>0) {
page.setTotalCount(list.get(0).intValue());
}
criteria.setProjection(null);//一定先清空查询条件 否则默认会发送select count(*) ...语句
//每页的数据(pageSize条记录)
List beanList = (List) this.getHibernateTemplate().findByCriteria(criteria, (pageCode-1)*pageSize, pageSize);
page.setBeanList(beanList);
return page;
}
}
package com.itheima.dao;
import java.util.List;
import com.itheima.domain.Customer;
public interface CustomerDao extends BaseDao{
List
package com.itheima.dao;
import java.util.List;
import com.itheima.domain.Customer;
/**
* 客户的持久层
* @author 寒面银枪
* 2019年7月2日-下午8:22:52
*/ //继承的时候传递了正确的类型就行了
public class CustomerDaoImpl extends BaseDaoImpl implements CustomerDao {
/*基本的增删改查都不用写了 BaseDaoImpl根据泛型已经都实现了通用的方法 */
/**
* 查询对应的来源(网络营销、电话营销分别有几个人)
*/
@Override
public List
package com.itheima.dao;
import java.util.List;
import com.itheima.domain.Dict;
public interface DictDao {
List findByCode(String dict_type_code);
}
package com.itheima.dao;
import java.util.List;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import com.itheima.domain.Dict;
public class DictDaoImpl extends HibernateDaoSupport implements DictDao {
/**
* 根据类别代码 查询字典对应项值 eg:006查询所有的客户级别可取的值
*/
@Override
public List findByCode(String dict_type_code) {
return (List) this.getHibernateTemplate().find("from Dict where dict_type_code = ?", dict_type_code);
}
}
package com.itheima.dao;
import com.itheima.domain.Linkman;
/**
* 联系人模块dao
* @author 寒面银枪
* 2019年7月6日-下午6:25:39
*/
public interface LinkmanDao extends BaseDao {
}
package com.itheima.dao;
import com.itheima.domain.Linkman;
public class LinkmanDaoImpl extends BaseDaoImpl implements LinkmanDao {
}
package com.itheima.dao;
import com.itheima.domain.User;
public interface UserDao {
User checkCode(String user_code);
void save(User user);
User login(User user);
}
package com.itheima.dao;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import com.itheima.domain.User;
/**
* 持久层:都可以继承HibernateDaoSupport (提供模板 注入sessionFactory即可)
* @author 寒面银枪
* 2019年7月3日-下午8:34:43
*/
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
/**
* 通过用户名进行验证
*/
@Override
public User checkCode(String user_code) {
/*DetachedCriteria criteria=DetachedCriteria.forClass(Use.class);
criteria.add(Restrictions.eq("user_code",user_code));
User user=(User) this.getHibernateTemplate().findByCriteria(criteria);
return user;*/
List list = (List) this.getHibernateTemplate().find("from User where user_code = ?",user_code);
if(list!=null && list.size()>0) {
return list.get(0);
}
return null;
}
/**
* 保存用户
*/
@Override
public void save(User user) {
this.getHibernateTemplate().save(user);
}
/**
* 用户登录:查询用户
* 通过登录名和密码和状态
*/
@Override
public User login(User user) {
//QBC 按条件查询
DetachedCriteria criteria=DetachedCriteria.forClass(User.class);
//拼接条件
criteria.add(Restrictions.eq("user_code", user.getUser_code()));
criteria.add(Restrictions.eq("user_password", user.getUser_password()));
criteria.add(Restrictions.eq("user_state", "1"));//注意直接写1
//查询
List list= (List) this.getHibernateTemplate().findByCriteria(criteria);
if(list!=null&&list.size()>0) {
return list.get(0);
}
return null;
}
}
package com.itheima.dao;
import com.itheima.domain.Visit;
public interface VisitDao extends BaseDao{
}
package com.itheima.dao;
import javax.annotation.Resource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.itheima.domain.Visit;
/**
* 客户拜访的持久层
* @author 寒面银枪
* 2019年7月7日-下午2:53:31
*/
@Repository(value="visitDao")
public class VisitDaoImpl extends BaseDaoImpl implements VisitDao {//实现dao别忘了
/*
* 注意:注入sessionfactory本来应该在父类BaseDaoImpl中写的 但由于之前都是配置文件方式,不好破坏BaseDaoImpl的结构,就直接在这里写了
*/
//注入sessionfactory
/*@Resource(name="sessionFactory")
private SessionFactory sessionFactory;
不行 报错 无法修改HibernateDaoSupprot中的sessionfactory属性进行注解
原因:父类HibernateDaoSupport的setSessionFacoty方法没有加注解@Autowired或者@Resource spring无法自动注入
mybatis的setSqlSessionFacoty方法就加了注解 避免了这个麻烦的问题
*/
@Resource(name="sessionFactory") //本来就在IOC的配置文件里 不怕,能直接拿到 内存(IOC容器)中有名称为sessionFactory的对象就注入
public void set2SessionFactory(SessionFactory sessionFactory) {
//关键 调用父类的set方法注入sessionFactory
super.setSessionFactory(sessionFactory);
}
/*//网上号称最简单的方式
@Autowired 按类型自动装配,只要内存中有sessionFactory对象 显然不如上面按名称注入的好
public void setMySessionFactory(SessionFactory sessionFactory){
super.setSessionFactory(sessionFactory);
} */
}
package com.itheima.domain;
import java.util.HashSet;
import java.util.Set;
import com.alibaba.fastjson.annotation.JSONField;
public class Customer {
private Long cust_id;//客户名称
private String cust_name;//客户姓名
private Long cust_user_id;//负责人id
private Long cust_create_id;//创建人id 这两个暂时不管
/*private String cust_source;//客户来源
private String cust_industry;//客户所属行业(eg:客户来自于百度 那么行业可以是互联网)
private String cust_level;//客户级别*/
private String cust_linkman;//联系人
private String cust_phone;//固定电话
private String cust_mobile;//移动电话
//一对多 多方写对象 那么上面普通字段的写法就要注释掉了
//一:客户来源 多:客户
private Dict source;
//一:客户行业 多:客户
private Dict industry;
//一:客户级别 多:客户
private Dict level;
// 上传文件保存的路径
private String filepath;
/**
* 和联系人配置一对多 (我:百度公司 有多个联系人:CEO、CFO等等...)
*
* customer(1)和linkman(多) 同样一方可以不写集合(此处还是写了,为了演示问题) 全部交给有外键的多方去配,有双方有一方维护外键就够了
* 客户写了联系人 联系人又写了客户 双方互相包含 真的会出现很多问题,不如不写呢 一方维护就行了呗
*/
@JSONField(serialize=false) //必须禁止set转json 否则就是死循环
private Set linkmans=new HashSet();
//一方这次似乎真的放弃的 都给多方去维护 不写多方的中间表了
public Long getCust_id() {
return cust_id;
}
public void setCust_id(Long cust_id) {
this.cust_id = cust_id;
}
public String getCust_name() {
return cust_name;
}
public void setCust_name(String cust_name) {
this.cust_name = cust_name;
}
public Long getCust_user_id() {
return cust_user_id;
}
public void setCust_user_id(Long cust_user_id) {
this.cust_user_id = cust_user_id;
}
public Long getCust_create_id() {
return cust_create_id;
}
public void setCust_create_id(Long cust_create_id) {
this.cust_create_id = cust_create_id;
}
public String getCust_linkman() {
return cust_linkman;
}
public void setCust_linkman(String cust_linkman) {
this.cust_linkman = cust_linkman;
}
public String getCust_phone() {
return cust_phone;
}
public void setCust_phone(String cust_phone) {
this.cust_phone = cust_phone;
}
public String getCust_mobile() {
return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
this.cust_mobile = cust_mobile;
}
public Dict getSource() {
return source;
}
public void setSource(Dict source) {
this.source = source;
}
public Dict getIndustry() {
return industry;
}
public void setIndustry(Dict industry) {
this.industry = industry;
}
public Dict getLevel() {
return level;
}
public void setLevel(Dict level) {
this.level = level;
}
public String getFilepath() {
return filepath;
}
public void setFilepath(String filepath) {
this.filepath = filepath;
}
public Set getLinkmans() {
return linkmans;
}
public void setLinkmans(Set linkmans) {
this.linkmans = linkmans;
}
}
package com.itheima.domain;
/**
* 数据字典表
* @author 寒面银枪
* 2019年7月4日-下午1:52:54
*/
public class Dict {
/**
* `dict_id` varchar(32) NOT NULL COMMENT '数据字典id(主键)',
`dict_type_code` varchar(10) NOT NULL COMMENT '数据字典类别代码',
`dict_type_name` varchar(64) NOT NULL COMMENT '数据字典类别名称',
`dict_item_name` varchar(64) NOT NULL COMMENT '数据字典项目名称',
`dict_item_code` varchar(10) DEFAULT NULL COMMENT '数据字典项目(可为空)',
`dict_sort` int(10) DEFAULT NULL COMMENT '排序字段',
`dict_enable` char(1) NOT NULL COMMENT '1:使用 0:停用',
`dict_memo` varchar(64) DEFAULT NULL COMMENT '备注',
*/
private String dict_id;//主键
private String dict_type_code;//数据字典类别代码 eg:01 06
private String dict_type_name;//数据字典类别名称 eg:01客户行业 06客户级别
private String dict_item_name;//数据字典项目名称 eg:01:教务培训|房地产 06:普通客户|VIP客户
private String dict_item_code;//数据字典项目(可为空)
private Integer dict_sort;//排序字段
private String dict_enable;//1:使用 0:停用
private String dict_memo;//备注
//并没有要查字典的需求 也即没有要查譬如某个级别的客户有多少个这种需求 那么就不必在一方这里写set集合了 正好外键一方维护也就够了
public String getDict_id() {
return dict_id;
}
public void setDict_id(String dict_id) {
this.dict_id = dict_id;
}
public String getDict_type_code() {
return dict_type_code;
}
public void setDict_type_code(String dict_type_code) {
this.dict_type_code = dict_type_code;
}
public String getDict_type_name() {
return dict_type_name;
}
public void setDict_type_name(String dict_type_name) {
this.dict_type_name = dict_type_name;
}
public String getDict_item_name() {
return dict_item_name;
}
public void setDict_item_name(String dict_item_name) {
this.dict_item_name = dict_item_name;
}
public String getDict_item_code() {
return dict_item_code;
}
public void setDict_item_code(String dict_item_code) {
this.dict_item_code = dict_item_code;
}
public Integer getDict_sort() {
return dict_sort;
}
public void setDict_sort(Integer dict_sort) {
this.dict_sort = dict_sort;
}
public String getDict_enable() {
return dict_enable;
}
public void setDict_enable(String dict_enable) {
this.dict_enable = dict_enable;
}
public String getDict_memo() {
return dict_memo;
}
public void setDict_memo(String dict_memo) {
this.dict_memo = dict_memo;
}
}
package com.itheima.domain;
/**
* 客户的联系人
* 多方
* @author Administrator
*/
public class Linkman {
/**
* `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
`lkm_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名',
`lkm_cust_id` bigint(32) NOT NULL COMMENT '客户id',
`lkm_gender` char(1) DEFAULT NULL COMMENT '联系人性别',
`lkm_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话',
`lkm_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机',
`lkm_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱',
`lkm_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq',
`lkm_position` varchar(16) DEFAULT NULL COMMENT '联系人职位',
`lkm_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注',
*/
private Long lkm_id;
private String lkm_name;
private String lkm_gender;
private String lkm_phone;
private String lkm_mobile;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo;
// 编写一个对象,不要自己new
private Customer customer;
public Long getLkm_id() {
return lkm_id;
}
public void setLkm_id(Long lkm_id) {
this.lkm_id = lkm_id;
}
public String getLkm_name() {
return lkm_name;
}
public void setLkm_name(String lkm_name) {
this.lkm_name = lkm_name;
}
public String getLkm_gender() {
return lkm_gender;
}
public void setLkm_gender(String lkm_gender) {
this.lkm_gender = lkm_gender;
}
public String getLkm_phone() {
return lkm_phone;
}
public void setLkm_phone(String lkm_phone) {
this.lkm_phone = lkm_phone;
}
public String getLkm_mobile() {
return lkm_mobile;
}
public void setLkm_mobile(String lkm_mobile) {
this.lkm_mobile = lkm_mobile;
}
public String getLkm_email() {
return lkm_email;
}
public void setLkm_email(String lkm_email) {
this.lkm_email = lkm_email;
}
public String getLkm_qq() {
return lkm_qq;
}
public void setLkm_qq(String lkm_qq) {
this.lkm_qq = lkm_qq;
}
public String getLkm_position() {
return lkm_position;
}
public void setLkm_position(String lkm_position) {
this.lkm_position = lkm_position;
}
public String getLkm_memo() {
return lkm_memo;
}
public void setLkm_memo(String lkm_memo) {
this.lkm_memo = lkm_memo;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
package com.itheima.domain;
import java.util.List;
/**
* 分页的JavaBean
* @author Administrator
*/
public class PageBean {
// 当前页
private int pageCode;
// 总页数
// private int totalPage; //不用属性 直接写方法就够了
// 总记录数(数据库总共多少条记录)
private int totalCount;
// 每页显示的记录条数
private int pageSize;
// 每页显示的数据
private List beanList;
public int getPageCode() {
return pageCode;
}
public void setPageCode(int pageCode) {
this.pageCode = pageCode;
}
/**
* 调用getTotalPage() 获取到总页数
* JavaBean的属性规定:totalPage是JavaBean是属性 ${pageBean.totalPage}
* @return
*/
public int getTotalPage() {
// 计算
int totalPage = totalCount / pageSize;
// 说明整除
if(totalCount % pageSize == 0){
return totalPage;
}else{
return totalPage + 1;
}
}
/*public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}*/
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public List getBeanList() {
return beanList;
}
public void setBeanList(List beanList) {
this.beanList = beanList;
}
}
package com.itheima.domain;
/**
* 用户的模块
* @author 寒面银枪
* 2019年7月3日-下午8:09:27
*/
public class User {
private Long user_id;//主键
private String user_code;//登录名称
private String user_name;//用户姓名
private String user_password;//密码
private String user_state;//用户状态 1正常 0暂停
public Long getUser_id() {
return user_id;
}
public void setUser_id(Long user_id) {
this.user_id = user_id;
}
public String getUser_code() {
return user_code;
}
public void setUser_code(String user_code) {
this.user_code = user_code;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public String getUser_password() {
return user_password;
}
public void setUser_password(String user_password) {
this.user_password = user_password;
}
public String getUser_state() {
return user_state;
}
public void setUser_state(String user_state) {
this.user_state = user_state;
}
/*写好javaBean立刻想着去写映射*/
}
package com.itheima.domain;
/**
* 客户拜访的javaBean
* @author 寒面银枪
* 2019年7月7日-下午2:14:47
*/
public class Visit {
/**
* `visit_id` VARCHAR(32) NOT NULL,
`visit_cust_id` BIGINT(32) DEFAULT NULL COMMENT '客户id',
`visit_user_id` BIGINT(32) DEFAULT NULL COMMENT '负责人id',
`visit_time` VARCHAR(32) DEFAULT NULL COMMENT '拜访时间',
`visit_interviewee` VARCHAR(32) DEFAULT NULL COMMENT '被拜访人',
`visit_addr` VARCHAR(128) DEFAULT NULL COMMENT '拜访地点',
`visit_detail` VARCHAR(256) DEFAULT NULL COMMENT '拜访详情',
`visit_nexttime` VARCHAR(32) DEFAULT NULL COMMENT '下次拜访时间',
*/
private String visit_id;//主键
private String visit_time;//拜访时间
private String visit_interviewee;//被拜访的人
private String visit_addr;//拜访地点
private String visit_detail;//拜访详情
private String visit_nexttime;//下次拜访时间
//外键 和客户 (中间表都是多方 多方对一方,一个对象)
private Customer customer;
//外键 和用户
private User user;
public String getVisit_id() {
return visit_id;
}
public void setVisit_id(String visit_id) {
this.visit_id = visit_id;
}
public String getVisit_time() {
return visit_time;
}
public void setVisit_time(String visit_time) {
this.visit_time = visit_time;
}
public String getVisit_interviewee() {
return visit_interviewee;
}
public void setVisit_interviewee(String visit_interviewee) {
this.visit_interviewee = visit_interviewee;
}
public String getVisit_addr() {
return visit_addr;
}
public void setVisit_addr(String visit_addr) {
this.visit_addr = visit_addr;
}
public String getVisit_detail() {
return visit_detail;
}
public void setVisit_detail(String visit_detail) {
this.visit_detail = visit_detail;
}
public String getVisit_nexttime() {
return visit_nexttime;
}
public void setVisit_nexttime(String visit_nexttime) {
this.visit_nexttime = visit_nexttime;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
package com.itheima.service;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import com.itheima.domain.Customer;
import com.itheima.domain.PageBean;
public interface CustomerService {
public void save(Customer customer);
public PageBean findByPage(Integer pageCode, Integer pageSize, DetachedCriteria criteria);
public Customer findById(Long cust_id);
public void delete(Customer customer);
public void update(Customer customer);
public List findAll();
public List findBySource();
}
package com.itheima.service;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.transaction.annotation.Transactional;
import com.itheima.dao.CustomerDao;
import com.itheima.domain.Customer;
import com.itheima.domain.PageBean;
/**
* 客户的业务层
* @author 寒面银枪
* 2019年7月2日-下午7:06:18
*/
@Transactional //下面的方法就都有了事务
public class CustomerServiceImpl implements CustomerService {
private CustomerDao customerDao;
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}
/**
* 保存客户
*/
public void save(Customer customer) {
customerDao.save(customer);
}
/**
* 分页查询
*/
@Override
public PageBean findByPage(Integer pageCode, Integer pageSize, DetachedCriteria criteria) {
return customerDao.findByPage(pageCode,pageSize,criteria);
}
/**
* 通过主键查询客户
*/
@Override
public Customer findById(Long cust_id) {
return customerDao.findById(cust_id);
}
/**
* 删除客户
*/
@Override
public void delete(Customer customer) {
customerDao.delete(customer);
}
/**
* 更新客户
*/
@Override
public void update(Customer customer) {
customerDao.update(customer);
}
/**
* 查询所有客户
*/
@Override
public List findAll() {
return customerDao.findAll();
}
/**
* 统计来源客户的数量
*/
@Override
public List findBySource() {
return customerDao.findBySource();
}
}
package com.itheima.service;
import java.util.List;
import com.itheima.domain.Dict;
public interface DictService {
List findByCode(String dict_type_code);
}
package com.itheima.service;
import java.util.List;
import org.springframework.transaction.annotation.Transactional;
import com.itheima.dao.DictDao;
import com.itheima.domain.Dict;
/**
* 字典业务层
* @author 寒面银枪
* 2019年7月4日-下午9:16:13
*/
@Transactional
public class DictServiceImpl implements DictService {
private DictDao dictDao;
public void setDictDao(DictDao dictDao) {
this.dictDao = dictDao;
}
/**
* 根据类别代码 查询字典对应项值 eg:006查询所有的客户级别可取的值
*/
@Override
public List findByCode(String dict_type_code) {
return dictDao.findByCode(dict_type_code);
}
}
package com.itheima.service;
import org.hibernate.criterion.DetachedCriteria;
import com.itheima.domain.Linkman;
import com.itheima.domain.PageBean;
public interface LinkmanService {
PageBean findByPage(Integer pageCode, Integer pageSize, DetachedCriteria criteria);
void save(Linkman model);
Linkman findById(Long lkm_id);
void delete(Linkman model);
void update(Linkman model);
}
package com.itheima.service;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.transaction.annotation.Transactional;
import com.itheima.dao.LinkmanDao;
import com.itheima.domain.Linkman;
import com.itheima.domain.PageBean;
@Transactional
public class LinkmanServiceImpl implements LinkmanService {
private LinkmanDao linkmanDao;
public void setLinkmanDao(LinkmanDao linkmanDao) {
this.linkmanDao = linkmanDao;
}
/**
* 分页查询
* @return
*/
public PageBean findByPage(Integer pageCode, Integer pageSize, DetachedCriteria criteria) {
return (PageBean) linkmanDao.findByPage(pageCode, pageSize, criteria);
}
/**
* 保存客户(添加记录)
*/
@Override
public void save(Linkman linkman) {
linkmanDao.save(linkman);
}
/**
* 根据Id查询联系人
*/
@Override
public Linkman findById(Long lkm_id) {
return linkmanDao.findById(lkm_id);
}
/**
* 删除联系人
*/
@Override
public void delete(Linkman linkman) {
linkmanDao.delete(linkman);
}
/**
* 修改联系人
*/
@Override
public void update(Linkman linkman) {
linkmanDao.update(linkman);
}
}
package com.itheima.service;
import com.itheima.domain.User;
public interface UserService {
User checkCode(String user_code);
void save(User user);
User login(User user);
}
package com.itheima.service;
import org.springframework.transaction.annotation.Transactional;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.utils.MD5Utils;
/**
* 用户的业务层 (业务层一创建 立刻写注解 配置事务 applicationContext拷贝过来的 事务管理器和事务注解都配好了)
* @author 寒面银枪
* 2019年7月3日-下午8:28:00
*/
@Transactional
public class UserServiceImpl implements UserService {
//事务注解写好 然后就立刻配置service IOC
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
/**
* 通过登录名进行校验
*/
@Override
public User checkCode(String user_code) {
return userDao.checkCode(user_code);
}
/**
* 保存用户 ,密码需要加密(导入工具类) 注意不加事务成功不了 是只读缓存 也即必须提交★
*/
@Override
public void save(User user) {
String pwd=user.getUser_password();
//给密码加密
user.setUser_password(MD5Utils.md5(pwd));
//用户默认1状态
user.setUser_state("1");
//调用持久层
userDao.save(user);
}
/**
* 登录;通过登录名和密码校验
* 注意密码先加密,再查询
*/
@Override
public User login(User user) {
String pwd=user.getUser_password();
//给密码加密
user.setUser_password(MD5Utils.md5(pwd));
return userDao.login(user);//都这么写 方法就有了通用性 保持好习惯
}
}
package com.itheima.service;
import org.hibernate.criterion.DetachedCriteria;
import com.itheima.domain.PageBean;
import com.itheima.domain.Visit;
public interface VisitService {
PageBean findByPage(Integer pageCode, Integer pageSize, DetachedCriteria criteria);
void save(Visit model);
}
package com.itheima.service;
import javax.annotation.Resource;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.itheima.dao.VisitDao;
import com.itheima.domain.PageBean;
import com.itheima.domain.Visit;
@Service(value="visitService")
@Transactional
public class VisitServiceImpl implements VisitService {
@Resource(name="visitDao")
private VisitDao visitDao;
/**
* 分页查询
*/
@Override
public PageBean findByPage(Integer pageCode, Integer pageSize, DetachedCriteria criteria) {
return visitDao.findByPage(pageCode, pageSize, criteria);
}
/**
* 保存拜访记录
*/
@Override
public void save(Visit visit) {
visitDao.save(visit);
}
}
package com.itheima.utils;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
public class FastJsonUtil {
/**
* 将对象转成json串
* @param object
* @return
*/
public static String toJSONString(Object object){
//DisableCircularReferenceDetect来禁止循环引用检测
return JSON.toJSONString(object,SerializerFeature.DisableCircularReferenceDetect);
}
/**
* 向浏览器写回json
*/
public static void write_json(HttpServletResponse response,String jsonString)
{
response.setContentType("application/json;utf-8");
response.setCharacterEncoding("UTF-8");
try {
response.getWriter().print(jsonString);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* ajax提交后回调的json字符串
* @return
*/
public static String ajaxResult(boolean success,String message)
{
Map map=new HashMap();
map.put("success", success);//是否成功
map.put("message", message);//文本消息
String json= JSON.toJSONString(map);
return json;
}
/**
* JSON串自动加前缀
* @param json 原json字符串
* @param prefix 前缀
* @return 加前缀后的字符串
*/
public static String JsonFormatterAddPrefix(String json,String prefix,Map newmap)
{
if(newmap == null){
newmap = new HashMap();
}
Map map = (Map) JSON.parse(json);
for(String key:map.keySet())
{
Object object=map.get(key);
if(isEntity(object)){
String jsonString = JSON.toJSONString(object);
JsonFormatterAddPrefix(jsonString,prefix+key+".",newmap);
}else{
newmap.put(prefix+key, object);
}
}
return JSON.toJSONString(newmap);
}
/**
* 判断某对象是不是实体
* @param object
* @return
*/
private static boolean isEntity(Object object)
{
if(object instanceof String )
{
return false;
}
if(object instanceof Integer )
{
return false;
}
if(object instanceof Long )
{
return false;
}
if(object instanceof java.math.BigDecimal )
{
return false;
}
if(object instanceof Date )
{
return false;
}
if(object instanceof java.util.Collection )
{
return false;
}
return true;
}
}
package com.itheima.utils;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Utils {
/**
* 使用md5的算法进行加密
*/
public static String md5(String plainText) {
byte[] secretBytes = null;
try {
secretBytes = MessageDigest.getInstance("md5").digest(
plainText.getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("没有md5这个算法!");
}
String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
// 如果生成数字未满32位,需要前面补0
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
return md5code;
}
public static void main(String[] args) {
System.out.println(md5("123"));
}
}
package com.itheima.utils;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import org.apache.commons.io.FileUtils;
public class UploadUtils {
/**
* 默认上传路径
*/
public static final String UPLOAD_PATH="E:/Tomcat/apache-tomcat-8.5.4/webapps/upload/";
public static String getUUIDName(String filename) {
//截取后缀名
String lastName=filename.substring(filename.lastIndexOf("."));
String firstName=UUID.randomUUID().toString().replace("-", "");
return firstName+lastName;
}
/**
* 整个下载的完全封装 在联系人里自己做
* @param uploadFileName 上传文件名
* @param upload 上传的文件
* @throws IOException
*/
public static void upload(String uploadFileName,File upload) throws IOException {
String uuidName = getUUIDName(uploadFileName);
File destFile=new File(UPLOAD_PATH+uuidName);
FileUtils.copyFile(upload, destFile);
}
public static void main(String[] args) {
System.out.println(getUUIDName("girl.jpg"));
}
}
package com.itheima.web.action;
import java.io.File;
import java.lang.reflect.ParameterizedType;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
/**
* 抽取Action父类 定义成抽象类最好
* @author 寒面银枪
* 2019年7月6日-下午6:38:45
*/
public abstract class BaseAction extends ActionSupport implements ModelDriven{
private static final long serialVersionUID = 1L;
/**
* Model的抽取
*/
private T model;
public BaseAction() {//必须要new一个实例 没办法
try {
//通过反射获取t真实类型
ParameterizedType pt=(ParameterizedType) this.getClass().getGenericSuperclass();
Class clazz= (Class) pt.getActualTypeArguments()[0];
//反射创建t的实例
model=clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
public T getModel() {
return model;
}
public void setModel(T model) {
this.model=model;//封装之后取当前model对象麻烦一点了
}
/**
* 分页查询的抽取 注意父类里get方法也要提供了
*/
private Integer pageCode=1;
public void setPageCode(Integer pageCode) {
if(pageCode==null) pageCode=1;
this.pageCode = pageCode;
}
public Integer getPageCode() {
return pageCode;
}
//每页显示的数据的条数 (如果可以让用户选择,那么就不能写死了)
private Integer pageSize=2;//默认2条
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getPageSize() {
return pageSize;
}
/**
* 上传下载也可以封装了 (前端file的name属性必须写upload了)
*/
private File upload;//要上传的文件 关键是这个麻烦的玩意儿 帮你封装好了 太强了
private String uploadFileName;//要上传的文件名
private String uploadContentType;//要上传的文件类型
public void setUpload(File upload) {
this.upload = upload;
}
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName;
}
public void setUploadContentType(String uploadContentType) {
this.uploadContentType = uploadContentType;
}
/**
* 向值栈设置值
* 调用值栈对象的set方法 一般应用于集合
*/
public void setVs(String key,Object obj) {
ActionContext.getContext().getValueStack().set(key,obj);
}
/**
* 向值栈设置值
* 调用值栈对象的push方法 一般应用于对象
*/
public void pushVs(Object obj) {
ActionContext.getContext().getValueStack().push(obj);
}
/**
* request、response、session的封装
*/
public HttpServletRequest getRequest() {
return ServletActionContext.getRequest();
}
public HttpServletResponse getResponse() {
return ServletActionContext.getResponse();
}
public HttpSession getSession() {
return ServletActionContext.getRequest().getSession();
}
//最后自己总结 抽取大框架
}
package com.itheima.web.action;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import com.itheima.domain.Customer;
import com.itheima.domain.Dict;
import com.itheima.domain.PageBean;
import com.itheima.service.CustomerService;
import com.itheima.utils.FastJsonUtil;
import com.itheima.utils.UploadUtils;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.util.ValueStack;
/**
* 客户的控制层(web层)
* @author 寒面银枪
* 2019年7月4日-下午2:45:06
*/
public class CustomerAction extends ActionSupport implements ModelDriven{
private static final long serialVersionUID = 1L;
/**
* 以后除非接收的单个参数使用属性驱动 否则都使用模型驱动封装数据 实现ModelDriven接口
* 多简单:实现接口 写一个javaBean属性 接口必须实现的方法内返回对象 即可
*/
private Customer customer=new Customer();//必须手动实例化
//类的属性是由get和set方法决定的 与字段无关 所以Action类有一个属性model
public Customer getModel() {
return customer;
}
//注入service 提供service成员属性
private CustomerService customerService;
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}//一旦Action给spring管理 Struts的自动注入就失效了 必须手动注入 既然Action在spring的xml中了 那么多配置一个属性就是了
/**
* 保存客户的方法
* @return
*/
public String add() {
System.out.println("web层保存客户...");
customerService.save(customer);
return NONE;
}
//属性驱动的方式封装当前页 默认值是1
private Integer pageCode=1;
public void setPageCode(Integer pageCode) {
if(pageCode==null) pageCode=1;
this.pageCode = pageCode;
}
//每页显示的数据的条数 (如果可以让用户选择,那么就不能写死了)
private Integer pageSize=2;//默认2条
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
/**
* 分页查询
*/
public String findByPage() {
//调用service web层可以提前拼条件了
DetachedCriteria criteria=DetachedCriteria.forClass(Customer.class);//注意不是写PageBean.class 查询谁写谁
//条件查询 多加几行拼条件的代码就行了
//拼接客户名称
String cust_name = customer.getCust_name();
if(cust_name!=null&&!cust_name.trim().isEmpty()) {
criteria.add(Restrictions.like("cust_name", "%"+cust_name+"%"));
}
//拼接客户级别
Dict level = customer.getLevel();
if(level!=null&&!level.getDict_id().trim().isEmpty()) {
criteria.add(Restrictions.eq("level.dict_id",level.getDict_id()));//后台也可以直接写level.dict_id 框架就是好啊
}
//拼接客户来源
Dict source = customer.getSource();
if(source!=null&&!source.getDict_id().trim().isEmpty()) {
criteria.add(Restrictions.eq("source.dict_id",source.getDict_id()));
}
//查询 默认不封装条件 就是查询所有
PageBean page = customerService.findByPage(pageCode,pageSize,criteria);
//压栈
//先获取值栈
ValueStack vs = ActionContext.getContext().getValueStack();
//栈顶是map<"page",page>
vs.set("page", page);
/**
* 若是对象用push方法,因为在栈顶,对象名都可以省略不写最简单
* 若是集合用set方法 ,最为方便 list[0].username jstl:foreach表达式一循环 u.username更简单了
*/
return "page";
}
/**
* 初始化到添加的页面
* @return
*/
public String initAddUI() {
return "initAddUI";
}
/**
* 文件的上传,需要在Action类中提供成员属性,属性的命名是有规则的!!
* private File upload; //类型File固定的 属性名必须和前端的name属性值一模一样 此属性表示要上传的文件
* private String uploadFileName; //前一半"upload"是前端的name值 后一半的"FileName"固定 表示上传文件的名称,且不会出现中文乱码
* private String uploadContentType;//前一半"upload"是前端的name值 后一半"ContentType"固定 表示上传文件的MIME类型
* 最后提供set方法 拦截器就会自动帮你注入值了 多好
*/
private File upload;//要上传的文件 关键是这个麻烦的玩意儿 帮你封装好了 太强了
private String uploadFileName;//要上传的文件名
private String uploadContentType;//要上传的文件类型
public void setUpload(File upload) {
this.upload = upload;
}
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName;
}
public void setUploadContentType(String uploadContentType) {
this.uploadContentType = uploadContentType;
}
/**
* 保存客户的方法
* @return
* @throws IOException
*/
public String save() throws IOException {
//处理文件上传
if(uploadFileName!=null) {
//说明用户选择了要上传的文件
/*System.out.println("文件名:"+uploadFileName);
System.out.println("文件类型:"+uploadContentType);*/
//把名称处理下 获得唯一名称 传入filename为了获取后缀名
String uuidname=UploadUtils.getUUIDName(uploadFileName);
//把文件上传到"E:\\Tomcat\\apache-tomcat-8.5.4\\webapps\\upload"
//默认上传路径以静态常量的形式放在上传工具类中了
//简单方式 新建一个文件 然后将封装的File upload文件copy到此新文件内
File file=new File(UploadUtils.UPLOAD_PATH+uuidname);//上面加了"//" 此处拼接时就不用加了
FileUtils.copyFile(upload, file);//导Apache.commons.io包
/*三行可以封装成一行*/
UploadUtils.upload(uploadFileName, upload);
//上传文件路径记录在数据库
customer.setFilepath(UploadUtils.UPLOAD_PATH+uuidname);
//如果一直用这个模板 可以全部封装成工具类 一行代码实现上传 当然3行也不多
}
customerService.save(customer);
return "save";
}
/**
* 删除客户
*/
public String delete() {
//删除客户
//先获取客户上传文件的路径 将客户上传的文件全删了
customer=customerService.findById(customer.getCust_id());
//获取上传文件的路径
String filepath=customer.getFilepath();
//删除客户
customerService.delete(customer);
//再删除文件 很简单
File file=new File(filepath);//先获取文件
if(file.exists()) {
file.delete();
}
return "delete";
}
/**
* 跳转到初始修改页面
*/
public String initUpdate() {
customer = customerService.findById(customer.getCust_id());//customer多例的 直接赋给customer没事 一次请求新new一个action
/*压栈 但是注意 返回值赋给了customer 而customer是setModel方法的返回值
也即Action属性 而Action默认压栈 所以customer就在值栈内了,eg: model.cust_name就可以取得客户姓名*/
return "initUpdate";
}
/**
* 修改客户功能
* @return
* @throws IOException
*/
public String update() throws IOException {
//判断是否上传新图片
if(uploadFileName!=null) {
//先删除旧图片
//上面upload是上传组件file传过来的 下面的旧的路径名是隐藏域传递过来的
String oldFilepath=customer.getFilepath();
if(oldFilepath!=null&&!oldFilepath.trim().isEmpty()) {
//说明旧的文件存在
File oldfile=new File(oldFilepath);
oldfile.delete();
}
//上传新图片
String uuidName = UploadUtils.getUUIDName(uploadFileName);
File file = new File(UploadUtils.UPLOAD_PATH+uuidName);
FileUtils.copyFile(upload, file);//这个复制工具类是Apache的
//把客户新图片的路径更新到数据库
customer.setFilepath(UploadUtils.UPLOAD_PATH+uuidName);
}
//上面的{}内的逻辑应该是原子性的 所以应该封装到service层去做 (万一删完出错了..咋办) 不应该在web层做的
//任务 进一步封装上传工具类 封装edit方法 (update方法留着 因为通用)
//更新客户的信息就ok了
customerService.update(customer);
return "update";
}
/**
* 查询所有客户 Adjx请求 不用跳转
* @return
*/
public String findAll() {
List list=customerService.findAll();
//转换成json
String jsonString = FastJsonUtil.toJSONString(list);
FastJsonUtil.write_json(ServletActionContext.getResponse(), jsonString);
return NONE;
}
/**
* 统计来源客户的数量
* @return
*/
public String findBySource() {
List list=customerService.findBySource();
//压栈
ValueStack vs = ActionContext.getContext().getValueStack();
//栈顶是map<"page",page>
vs.set("sourcelist", list);
return "findBySource";
}
}
package com.itheima.web.action;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import com.itheima.domain.Dict;
import com.itheima.service.DictService;
import com.itheima.utils.FastJsonUtil;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
/**
* 字典控制器0
* @author 寒面银枪
* 2019年7月4日-下午7:12:59
*/
public class DictAction extends ActionSupport implements ModelDriven{
private Dict dict=new Dict();
public Dict getModel() {
return dict;
}
private DictService dictService;
public void setDictService(DictService dictService) {
this.dictService = dictService;
}
/**
* 通过字段的type_code值查询客户级别或者客户来源
*/
public String findByCode() {
//调用业务层去查
List list = (List)dictService.findByCode(dict.getDict_type_code());
//使用fastJson把list转成json字符串
String jsonString = FastJsonUtil.toJSONString(list);
//把json字符串写浏览器
HttpServletResponse response = ServletActionContext.getResponse();
FastJsonUtil.write_json(response, jsonString);
return NONE;
}
}
package com.itheima.web.action;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import com.itheima.domain.Customer;
import com.itheima.domain.Linkman;
import com.itheima.domain.PageBean;
import com.itheima.service.LinkmanService;
public class LinkmanAction extends BaseAction{
private static final long serialVersionUID = 1L;
private LinkmanService linkmanService;
public void setLinkmanService(LinkmanService linkmanService) {
this.linkmanService = linkmanService;
}
/**
* 分页查询
* @return
*/
public String findByPage() {
//调用业务层分页查询
DetachedCriteria criteria = DetachedCriteria.forClass(Linkman.class);
//封装查询条件 "名称"和"所属客户"
//先获取然后判断null,去空格 ,养成习惯
String lkm_name = getModel().getLkm_name();
if(lkm_name!=null&&!lkm_name.trim().isEmpty()) {
criteria.add(Restrictions.like("lkm_name", "%"+lkm_name+"%"));
}
//Long cust_id = getModel().getCustomer().getCust_id();//注意写法
Customer c = getModel().getCustomer();
if(c!=null&&c.getCust_id()!=null) {
criteria.add(Restrictions.eq("customer.cust_id", c.getCust_id()));
}
//调用service查询
PageBean page = linkmanService.findByPage(this.getPageCode(),this.getPageSize(),criteria);
//压栈
this.setVs("page", page);
return "page";
}
/**
* 新增联系人UI
*/
public String initAddUI() {
return "initAddUI";
}
/**
* 新增联系人
*/
public String save() {
linkmanService.save(getModel());
return "save";
}
/**
* 删除联系人
*/
public String delete() {
//先查再删
setModel(linkmanService.findById(getModel().getLkm_id()));
//肯定有 就不判断了
linkmanService.delete(getModel());
return "delete";
}
/**
* 修改联系人UI
*/
public String initUpdate() {
setModel(linkmanService.findById(getModel().getLkm_id()));//设置到model的好处 默认压栈
return "initUpdate";
}
/**
* 修改联系人
*/
public String update() {
linkmanService.update(getModel());
return "update";
}
}
package com.itheima.web.action;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import com.itheima.domain.User;
import com.itheima.service.UserService;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
/**
* 用户的控制器
* @author 寒面银枪
* 2019年7月3日-下午8:19:21
*/
public class UserAction extends ActionSupport implements ModelDriven{
//模型驱动: 实现接口 提供对象属性 实现接口方法内返回对象属性 即可帮你封装数据
private User user=new User();
public User getModel() {
return user;
}
//Action写好后及时到applicationContext.xml配置-》然后到struts.xml配置
//注入service
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public String regist() {
userService.save(user);
return LOGIN;
}
/**
* 通过登录名判断登录名是否存在
* @return
*/
public String checkCode() {
//已经有model了 user对象里也有user_code了 那么肯定也自动封装到user对象里了 直接查即可 json格式,但是框架肯定也能封装 毕竟也是key-value呀
User u=userService.checkCode(user.getUser_code());
//获取request对象 用Struts2一个强大的类 ServletActionContext
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("text/html;charset=UTF-8");
try {
//获得输出流
PrintWriter writer = response.getWriter();
//判断
if(u!=null) {
//登录名被查到了 已经被占用了
writer.print("no");
}else {
//登录名是新的未注册过的
writer.print("yes");
}
} catch (IOException e) {
e.printStackTrace();
}
return NONE;//adjx不用跳 直接输出流写即可
}
/**
* 登录功能
* @return
*/
public String login() {
User existUser = userService.login(user);
if(user==null) {
//登录失败
return LOGIN;
}else {
//登录成功
ServletActionContext.getRequest().getSession().setAttribute("user", existUser);
return "loginOK";
}
}
/**
* 安全退出登录
*/
public String logOut() {
ServletActionContext.getRequest().getSession().removeAttribute("user");
return LOGIN;
}
}
package com.itheima.web.action;
import javax.annotation.Resource;
import javax.annotation.Resources;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.itheima.domain.PageBean;
import com.itheima.domain.User;
import com.itheima.domain.Visit;
import com.itheima.service.VisitService;
/**
* 客户拜访的控制器
* @author 寒面银枪
* 2019年7月7日-下午2:38:30
*/
/*
下面两行配置等价于
*/
@Controller(value="visitAction")
@Scope(value="prototype")
public class VisitAction extends BaseAction{
private static final long serialVersionUID = -139853886677968072L;
@Resource(name="visitService") //按名称注入
private VisitService visitService;
//条件查询的起止日期
private String beginDate;
private String endDate;
public void setBeginDate(String beginDate) {
this.beginDate = beginDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
//也提供get方法 方便前台获取值
public String getBeginDate() {
return beginDate;
}
public String getEndDate() {
return endDate;
}
/**
* 分页查询:
* 查询客户的拜访记录,根据用户的主键查询 (客户Customer拜访用户user)
* select * from sale_visit where visit_user_id = ?
* @return
*/
public String findByPage() {
//先获取当前登录的用户
User user= (User) getSession().getAttribute("user");
//判断 虽然..但是养成好习惯呗
if(user==null) {
return LOGIN;
}
//查询该用户(其实是公司负责人)下所有拜访记录
DetachedCriteria criteria=DetachedCriteria.forClass(Visit.class);
//条件查询 筛选条件的拼接
if(beginDate!=null&&!beginDate.trim().isEmpty()) {
criteria.add(Restrictions.ge("visit_time", beginDate));
}
if(endDate!=null&&!endDate.trim().isEmpty()) {
criteria.add(Restrictions.le("visit_time", endDate));
}
//添加查询的其他条件
criteria.add(Restrictions.eq("user.user_id", user.getUser_id()));
//分页查询
PageBean page = visitService.findByPage(this.getPageCode(),this.getPageSize(),criteria);
this.setVs("page", page);
return "page";
}
/**
* 新增拜访UI
* @return
*/
public String initSave() {
return "initSave";
}
/**
* 保存拜访记录
*/
public String save() {
//需要查到当前用户 一同存入数据库
User user= (User) getSession().getAttribute("user");
if(user==null) {
return LOGIN;
}
getModel().setUser(user);
//保存数据
visitService.save(getModel());
return "save";
}
}
package com.itheima.web.interceptor;
import org.apache.struts2.ServletActionContext;
import com.itheima.domain.User;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
/**
* 用户拦截器 过滤没有登录的
* 判断用户是否登录
* 若登录:执行下一个拦截器
* 否则:返回到登录页面(注意有些页面要放行,login和regist)
*
* 继承指定拦截器
* @author 寒面银枪
* 2019年7月7日-下午6:02:19
*/
public class UserInterceptor extends MethodFilterInterceptor{
private static final long serialVersionUID = -733814691331866464L;
/**
* 拦截目标Action方法
*/
protected String doIntercept(ActionInvocation invocation) throws Exception {
//获取session
User user=(User)ServletActionContext.getRequest().getSession().getAttribute("user");
if(user==null) {
return "login";
}
//执行下一个拦截器
return invocation.invoke();
}
}
org.hibernate.dialect.MySQLDialect
true
true
update
com/itheima/domain/User.hbm.xml
com/itheima/domain/Customer.hbm.xml
com/itheima/domain/Dict.hbm.xml
com/itheima/domain/Linkman.hbm.xml
com/itheima/domain/Visit.hbm.xml
/login.jsp
/jsp/customer/list.jsp
/jsp/customer/add.jsp
customer_findByPage
/jsp/error.jsp
customer_findByPage.action
/jsp/customer/edit.jsp
customer_findByPage.action
/jsp/totals/sources.jsp
.jpg,.txt
209715200
/index.jsp
login,regist,checkCode
/jsp/linkman/list.jsp
/jsp/linkman/add.jsp
linkman_findByPage.action
linkman_findByPage.action
/jsp/linkman/edit.jsp
linkman_findByPage.action
/jsp/visit/list.jsp
/jsp/visit/add.jsp
visit_findByPage.action
crm_28
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
classpath:applicationContext.xml
OpenSessionInViewFilter
org.springframework.orm.hibernate5.support.OpenSessionInViewFilter
OpenSessionInViewFilter
/*
struts2
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
struts2
/*
500
/jsp/error.jsp
login.jsp
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c\:mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=info, stdout
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
客户关系管理系统
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
导航