ssm框架项目|ssm项目(商城管理系统)-- 完整


搭建SSM项目

  • 1. 新建Maven工程,添加Web模板
  • 2. 配置 pom.xml文件
    • 2.1 集中定义全局变量 : 依赖版本号 (方便管理版本)
    • 2.2 依赖
    • 2.3 插件
    • 2.4 识别配置文件
  • 3. 添加配置文件
    • 3.1 数据库连接信息jdbc.properties文件配置
    • 3.2 MyBatis核心配置文件mybatis-config.xml
    • 3.3 Spring配置文件
      • 3.3.1 数据持久层 -- applicationContext_dao.xml
      • 3.3.2 业务逻辑层 -- applicationContext_service.xml
    • 3.4 springMVC配置文件springmvc.xml
  • 4. 设置web.xml文件
    • 4.1 添加字符编码过滤器
    • 4.2 注册SpringMVC框架
    • 4.3 注册Spring框架
  • 5. 使用Mabatis逆向工程生成pojo和mapper
    • 5.1 导入逆向工程
    • 5.2 修改配置文件
    • 5.3 运行GeneratorSqlmap,生成pojo和mapper文件
    • 5.4 MyBatis逆向工程中的Mapper接口以及Example的实例函数及详解
  • 6. 添加MD5加密算法(保护密码)
  • 7. 实现登录功能
    • 7.1 业务逻辑层 -- 创建AdminService接口,添加登录login
    • 7.2 业务逻辑层 -- 创建AdminServiceImpl,实现AdminService接口登录login
    • 7.3 界面控制层 -- 创建AdminAtion,添加login,判断是否登陆成功,并跳转相应页面
  • 8. 实现查询所有商品数据
    • 8.1 业务逻辑层 -- 创建ProductInfoService接口,添加查询所有商品功能getAll
    • 8.2 业务逻辑层 -- 创建ProductInfoServiceImpl,实现getAll
    • 8.3 界面控制层 -- 创建ProductInfoAtion,添加getAll,传递数据到前台
  • 9. 实现分页展示 --Ajax异步 -- mybatis插件pagehelper
    • 9.1 业务逻辑层 -- ProductInfoService接口中,添加分页功能splitPage
    • 9.2 业务逻辑层 -- ProductInfoServiceImpl中,实现splitPage,完成分页
    • 9.3 界面控制层 -- ProductInfoAtion中,添加splitPage,传递数据到前台product.jsp
    • 9.4 product.jsp前台接收数据展示,设置分页栏
    • 9.5 分页的AJAX实现
    • 9.6 界面控制层 -- ProductInfoAtion中,添加ajaxSplit,对ajax进行解析完成分页
  • 10 . 商品类别下拉选项实现 -- 监听器实现(自动查询并存入全局对象中)
    • 10.1 业务逻辑层 -- 实现获取所有类别数据
      • 创建ProductTypeService接口,定义获取所有类别数据方法getAll
      • 创建ProductTypeServiceImpl实现接口的所有类别数据方法getAll
    • 10.2 通过监听器自动查询并存入全局对象中
    • 10.3 前端下拉框显示类别
  • 11. 上传文件 --ajax异步上传并回显 -- springMVC组件
    • 11.1 前端上传图片
      • 文件选择
      • Ajax异步提交事件 -- 采用ajaxfileupload.js文件(封装ajax异步上传的功能)
    • 11.2 在ProductInfoAction中添加异步Ajax文件上传处理
      • Ajax文件上传处理并返回含图片位置的json对象用于回显图片
      • FileNameUtil工具类 -- 用于UUID文件名防止重复
  • 12 . 新增商品功能
    • 12.1 业务逻辑层 -- 实现新增商品
      • ProductInfoService接口添加save方法
      • ProductInfoServiceImpl实现类实现save
    • 12.2 界面控制层 -- ProductInfoAtion中,添加save完成添加,返回初始页
  • 13. 更新商品
    • 13.1 根据主键id查询商品,用于修改数据 - getById方法
      • 业务逻辑层 -- ProductInfoService接口添加getById方法
      • 业务逻辑层 -- ProductInfoServiceImpl实现类实现getById
      • 界面控制层 -- ProductInfoAtion中,添加one方法完成查询,返回修改页
    • 13.3 前端点击编辑,跳转one方法根据主键id查询所要修改的数据,回显
    • 13.3 更新前端页面 -- 主要代码
    • 13.4 修改数据 - update方法
      • 业务逻辑层 -- ProductInfoService接口添加update方法
      • 业务逻辑层 -- ProductInfoServiceImpl实现类实现update
      • 界面控制层 -- ProductInfoAtion中,添加update完成更新
  • 14. ajax批量删除
    • 14.1 前端点击触发
    • 14.2 在mapper中添加操作语句(复杂操作)
    • 14.3 实现删除

1. 新建Maven工程,添加Web模板 创建Maven项目后没有webapp目录所以我们要添加web模块,
ssm框架项目|ssm项目(商城管理系统)-- 完整
文章图片

这里通过手动添加web模块,这种通过手动添加web模块方式创建的web项目是非常纯净的,没有任何附加的代码,开发中推荐。也可以使用maven的模板(在创建Maven时选择模板)创建web项目
如下图所示,添加web模块
ssm框架项目|ssm项目(商城管理系统)-- 完整
文章图片

ssm框架项目|ssm项目(商城管理系统)-- 完整
文章图片

2. 配置 pom.xml文件 2.1 集中定义全局变量 : 依赖版本号 (方便管理版本)
4.12 >5.2.5.RELEASE 3.5.1 1.3.1 1.2.15 8.0.22 >1.6.4 1.1.12 5.1.2 1.2 >3.0.1 2.0 2.9.6

2.2 依赖 在 ... 中添加依赖
spring 所需要的依赖
org.springframework spring-context ${spring.version} org.springframework spring-beans ${spring.version} org.springframework spring-webmvc ${spring.version} org.springframework spring-jdbc ${spring.version} org.springframework spring-aspects ${spring.version} org.springframework spring-jms ${spring.version} org.springframework spring-context-support ${spring.version} org.springframework spring-test ${spring.version}

Mybatis相关依赖
org.mybatis mybatis ${mybatis.version} org.mybatis mybatis-spring ${mybatis.spring.version} com.github.miemiedev mybatis-paginator ${mybatis.paginator.version} com.github.pagehelper pagehelper ${pagehelper.version}

数据库相关的依赖
mysql mysql-connector-java ${mysql.version} com.alibaba druid ${druid.version}

单元测试依赖
junit junit ${junit.version} >test

JSP相关依赖
jstl jstl ${jstl.version} javax.servlet javax.servlet-api 3.0.1 >provided javax.servlet jsp-api >provided ${jsp-api.version}

ackson Json处理工具包
com.fasterxml.jackson.core jackson-databind ${jackson.version}

文件异步上传
commons-io commons-io 2.4 commons-fileupload commons-fileupload 1.3.1

2.3 插件 在 ... 中添加插件
jdk 编译版本
org.apache.maven.plugins maven-compiler-plugin >1.8 1.8 UTF-8

2.4 识别配置文件 在 ... 中添加
src/main/java **/*.properties **/*.xml false src/main/resources **/*.properties **/*.xml false

3. 添加配置文件 3.1 数据库连接信息jdbc.properties文件配置
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mimissm?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true jdbc.username=root jdbc.password=root

3.2 MyBatis核心配置文件mybatis-config.xml mybatis大部分功能被spring接管,在这里分页pagehelper无法被spring接管,所以配置分页即可

3.3 Spring配置文件 对spring配置文件按照分层进行拆分
3.3.1 数据持久层 – applicationContext_dao.xml
其中实体类pojo和mapper文件夹未创建,后面通过mybatis逆向工程生成

3.3.2 业务逻辑层 – applicationContext_service.xml

3.4 springMVC配置文件springmvc.xml springmvc.xml

4. 设置web.xml文件 4.1 添加字符编码过滤器
注:字符编码过滤器需放在web.xml顶端
encode org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 forceRequestEncoding ture forceResponseEncoding ture encode /*

4.2 注册SpringMVC框架
> >springmvc >org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springmvc.xml > >springmvc *.action

4.3 注册Spring框架
spring配置文件若在WEB-INF目录下,会自动加载,在其他位置要手动加载
加载多个文件时有两个方法
1. 逗号隔开 :classpath:applicationContext_dao.xml,classpath:applicationContext_service.xml
2. 使用通配符 :classpath:applicationContext_*.xml (代表以 applicationContext_ 为前缀以.xml为后缀的文件)
org.springframework.web.context.ContextLoaderListener contextConfigLocationclasspath:applicationContext_*.xml

5. 使用Mabatis逆向工程生成pojo和mapper 5.1 导入逆向工程 逆向工程简称MBG,是一个专门为MyBatis框架使用者定制的代码生成器,可以快速的根据表生成对应的映射文件,接口,以及bean类。支持基本的增删改查,以及QBC风格的条件查询。但是表连接、存储过程等这些复杂sqI的定义需要我们手工编写
  • 官方文档地址http://www.mybatis.org/generator/
  • 官方工程地址 https://github.com/mybatis/generator/releases
ssm框架项目|ssm项目(商城管理系统)-- 完整
文章图片

5.2 修改配置文件 在generatorConfig.xml中配置Mapper生成的详细信息,如下图:
ssm框架项目|ssm项目(商城管理系统)-- 完整
文章图片

注意修改内容主要以下几点:
  1. 修改数据库连接的信息

  2. 指定数据库表 (生成那些数据库表对应的文件) – admin,product_info,product_type

  3. 生成PO类的位置 – com.yanyu.pojo

  4. mapper映射文件生成的位置 – com.yanyu.mapper
    targetPackage="com.yanyu.mapper" targetProject=".\src">

  5. mapper接口生成的位置

5.3 运行GeneratorSqlmap,生成pojo和mapper文件 ssm框架项目|ssm项目(商城管理系统)-- 完整
文章图片

运行前删除src下同名目录,防止文件重叠
运行程序后,在设置的目录下生成对应文件
ssm框架项目|ssm项目(商城管理系统)-- 完整
文章图片

5.4 MyBatis逆向工程中的Mapper接口以及Example的实例函数及详解 参考:https://blog.csdn.net/qq_44058265/article/details/120460879
6. 添加MD5加密算法(保护密码)
  1. MD5(message-digest algorithm 5)信息摘要算法,
    它的长度一般是32位的16进制数字符串(如81dc9bdb52d04dc20036dbd8313ed055)
  2. 由于系统密码明文存储容易被黑客盗取
  3. 应用:注册时,将密码进行md5加密,存到数据库中,防止可以看到数据库数据的人恶意篡改。
    登录时,将密码进行md5加密,与存储在数据库中加密过的密码进行比对
  4. md5不可逆,即没有对应的算法,从产生的md5值逆向得到原始数据。
    但是可以使用暴力破解,这里的破解并非把摘要还原成原始数据,如暴力枚举法。
MD5Util工具类
package com.yanyu.utils; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5Util { public final static String getMD5(String str){ try { MessageDigest md = MessageDigest.getInstance("SHA"); //创建具有指定算法名称的摘要 md.update(str.getBytes()); //使用指定的字节数组更新摘要 byte mdBytes[] = md.digest(); //进行哈希计算并返回一个字节数组String hash = ""; for(int i= 0; i

测试
@Test public void testMD5(){ String md5 = MD5Util.getMD5("000000"); System.out.println(md5); //c984aed014aec7623a54f0591da07a85fd4b762d }

7. 实现登录功能 7.1 业务逻辑层 – 创建AdminService接口,添加登录login AdminService
package com.yanyu.service; import com.yanyu.pojo.Admin; public interface AdminService { Admin login(String name,String pwd); }

7.2 业务逻辑层 – 创建AdminServiceImpl,实现AdminService接口登录login 通过数据访问层对象AdminMapper,查找数据,成功返回用户数据,失败返回null
AdminServiceImpl
package com.yanyu.service.impl; import ...@Service public class AdminServiceImpl implements AdminService {//数据访问层对象,spring自动创建注入 @Autowired AdminMapper adminMapper; @Override public Admin login(String name, String pwd) {//根据用户名在数据库查找用户 //使用AdminExample对象来封装条件 AdminExample example = new AdminExample(); /* select * from admin where a_name = 'admin' */ //添加用户名a_name = 'admin'条件 example.createCriteria().andANameEqualTo(name); //执行查询 List adminList = adminMapper.selectByExample(example); if(adminList.size()>0){ Admin admin = adminList.get(0); //进行密码对比判断 - 密码是密文 String md5 = MD5Util.getMD5(pwd); /* System.out.println(admin.getaPass()+""+md5); */ if(md5.equals(admin.getaPass())){ return admin; } }return null; } }

7.3 界面控制层 – 创建AdminAtion,添加login,判断是否登陆成功,并跳转相应页面 调用业务逻辑层对象AdminServiceImpl,获取登录信息,登陆成功,跳转到main.jsp页面,登陆失败,跳转到login.jsp页面
AdminAtion
package com.yanyu.controller; import ...@Controller @RequestMapping("/admin") public class AdminAction {//业务逻辑层对象 @Autowired AdminService adminService; //实现登陆的判断,进行相应跳转、 @RequestMapping("/login") public String login(String name, String pwd, HttpServletRequest request){ Admin admin = adminService.login(name,pwd); if(admin!=null){ //登陆成功,跳转到main.jsp页面(视图解析器) request.setAttribute("admin",admin); // 存储用户信息 return "main"; }else { //登陆失败,跳转到login.jsp页面(视图解析器) request.setAttribute("errmsg","用户名或密码不正确!"); //返回失败信息 return "login"; } }}

8. 实现查询所有商品数据 8.1 业务逻辑层 – 创建ProductInfoService接口,添加查询所有商品功能getAll ProductInfoService
package com.yanyu.service; import ...public interface ProductInfoService { //显示所有商品、 List getAll(); }

8.2 业务逻辑层 – 创建ProductInfoServiceImpl,实现getAll ProductInfoServiceImpl
package com.yanyu.service.impl; import ...@Service public class ProductInfoServiceImpl implements ProductInfoService { //数据访问层对象 @Autowired ProductInfoMapper productInfoMapper; @Override public List getAll() { //没有条件,查询所有 return productInfoMapper.selectByExample(new ProductInfoExample()); } }

8.3 界面控制层 – 创建ProductInfoAtion,添加getAll,传递数据到前台
package com.yanyu.controller; import ...@Controller @RequestMapping("/prod") public class ProductInfoAction { //业务逻辑层对象 @Autowired ProductInfoService productInfoService; //显示所有商品 @RequestMapping("/getAll") public String getAll(HttpServletRequest request){ List list = productInfoService.getAll(); //传递数据 request.setAttribute("list",list); //跳转页面 return "product"; } }

9. 实现分页展示 --Ajax异步 – mybatis插件pagehelper 9.1 业务逻辑层 – ProductInfoService接口中,添加分页功能splitPage PageInfo由分页插件pagehelper提供(PageInfo页面数据类,包含当前页,页大小,当前页大小,当前页数据…),pageNum当前页,pageSize页的大小
//分页功能,PageInfo由分页插件pagehelper提供,pageNum当前页,pageSize页的大小 PageInfo splitPage(int pageNum,int pageSize);

9.2 业务逻辑层 – ProductInfoServiceImpl中,实现splitPage,完成分页
@Override public PageInfo splitPage(int pageNum, int pageSize) { //分页插件使用PageHelper工具类完成分页设置(),放在取数据集合之前 PageHelper.startPage(pageNum,pageSize); //条件查询 - 主键降序 select* from product_info order by p_id desc ProductInfoExample example =new ProductInfoExample(); //添加条件order by p_id desc example.setOrderByClause("p_id desc"); //查询数据,分页设置PageHelper要放在取数据集合之前 List list = productInfoMapper.selectByExample(example); //将数据封装进PageInfo中,PageInfo自动对list进行分页 PageInfo pageInfo = new PageInfo<>(list); return pageInfo; }

9.3 界面控制层 – ProductInfoAtion中,添加splitPage,传递数据到前台product.jsp 显示初始页数据(第一页的5条数据)到前台 , 翻页由ajax异步来完成
设置每页显示记录数常量PAGE_SIZE,方便修改
//每页显示记录数 public static final int PAGE_SIZE = 5 ; //显示初始页数据(第一页的5条数据) @RequestMapping("/split") public String split(HttpServletRequest request){ //得到第一页数据 PageInfo info = productInfoService.splitPage(1,PAGE_SIZE); request.setAttribute("info",info); return "product"; }

9.4 product.jsp前台接收数据展示,设置分页栏 前台接收初始页数据,通过ajax翻页,ajax传到界面控制层 – ProductInfoAtion中进行分页
    全选
商品名 商品介绍 定价(元) 商品图片 商品数量 操作
${p.pName} ${p.pContent} ${p.pPrice} ssm框架项目|ssm项目(商城管理系统)-- 完整
文章图片
${p.pNumber}
暂时没有符合条件的商品!

9.5 分页的AJAX实现
type="text/javascript"> function ajaxsplit(page) { //异步ajax分页请求 $.ajax({ url:"${pageContext.request.contextPath}/prod/ajaxSplit.action", data:{"page":page}, type:"post", success:function () { //重新加载分页显示的组件table //location.href---->http://localhost:8080/admin/login.action $("#table").load("http://localhost:8080/admin/product.jsp #table"); } }) };

9.6 界面控制层 – ProductInfoAtion中,添加ajaxSplit,对ajax进行解析完成分页
//ajax分页处理 //解析ajax请求,返回客户端 @ResponseBody @RequestMapping("/ajaxSplit") public void ajaxSplit(int page, HttpSession session){ //取得当前页page的数据 PageInfo info = productInfoService.splitPage(page,PAGE_SIZE); System.out.println(info.getList()); session.setAttribute("info",info); }

10 . 商品类别下拉选项实现 – 监听器实现(自动查询并存入全局对象中) 10.1 业务逻辑层 – 实现获取所有类别数据 创建ProductTypeService接口,定义获取所有类别数据方法getAll
package com.yanyu.service; package ...public interface ProductTypeService { List getAll(); }

创建ProductTypeServiceImpl实现接口的所有类别数据方法getAll
package com.yanyu.service.impl; import ...@Service("ProductTypeServiceImpl") public class ProductTypeServiceImpl implements ProductTypeService { //数据访问层对象 @Autowired ProductTypeMapper productTypeMapper; @Override public List getAll() { return productTypeMapper.selectByExample(new ProductTypeExample()); }}

10.2 通过监听器自动查询并存入全局对象中
【ssm框架项目|ssm项目(商城管理系统)-- 完整】spring容器的注册是通过监听器,与该对象是同一个监听器,无法确定谁先创建,所以无法使用spring的自动装配,需手动从Spring容器取出ProductTypeServiceImpl对象
package com.yanyu.listener; import ...@WebListener public class ProductTypeListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { //手动从Spring容器取出ProductTypeServiceImpl对象 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_*.xml"); ProductTypeService productTypeService = (ProductTypeService) context.getBean("ProductTypeServiceImpl"); List typeList = productTypeService.getAll(); //放入全局作用域中 sce.getServletContext().setAttribute("typeList",typeList); }@Override public void contextDestroyed(ServletContextEvent sce) {} }

10.3 前端下拉框显示类别
类别 name="typeId">

11. 上传文件 --ajax异步上传并回显 – springMVC组件 11.1 前端上传图片 文件选择
图片介绍




id="imgName" >

Ajax异步提交事件 – 采用ajaxfileupload.js文件(封装ajax异步上传的功能)
="text/javascript" src="https://www.it610.com/article/${pageContext.request.contextPath }/js/ajaxfileupload.js">="text/javascript"> function fileChange(){//注意:此处不能使用jQuery中的change事件,因此仅触发一次,因此使用标签的:onchange属性 $.ajaxFileUpload({ url: '/prod/ajaxImg.action',//用于文件上传的服务器端请求地址 secureuri: false,//是否需要安全协议一般设置为false fileElementId: 'pimage',//文件上传控件的id属性 dataType: 'json',//返回值类型 一般设置为json success: function(obj) //服务器成功响应处理函数 { $("#imgDiv").empty(); //清空原有数据 //创建img 标签对象 var imgObj = $("ssm框架项目|ssm项目(商城管理系统)-- 完整
文章图片




id="imgName">
... 总数量 ... //取出全局中的数据,与修改商品的类别id对比,selected="selected"表示选中 类别 name="typeId">

13.4 修改数据 - update方法 业务逻辑层 – ProductInfoService接口添加update方法
//更新商品 int update(ProductInfo info);

业务逻辑层 – ProductInfoServiceImpl实现类实现update
@Override public int update(ProductInfo info) { return productInfoMapper.updateByPrimaryKey(info); }

界面控制层 – ProductInfoAtion中,添加update完成更新
@RequestMapping("/update") public String update(ProductInfo info,HttpServletRequest request){ //判断是否有重新上传的图片,若有则修改图片地址,没有不变 if(!uuidFileName.equals("")) { info.setpImage(uuidFileName); } //num受影响行数 int num=0; try { num = productInfoService.update(info); } catch (Exception e) { e.printStackTrace(); } if(num>0){ request.setAttribute("msg","更新成功!"); }else{ request.setAttribute("msg","更新失败!"); } //转发到所有商品初始页 return "forward:/prod/split.action"; }

14. ajax批量删除 14.1 前端点击触发
//批量删除 function deleteBatch() {//取得所有被选中删除商品的pid var cks=$("input[name=ck]:checked"); //判断是否有选中的商品 if(cks.length==0){ // 没有选中的商品 alert("请选择将要删除的商品!"); }else{ var str=""; var id=""; // 有选中的商品,则取出每个选中商品的ID,拼接提交的ID的数据 if(confirm("您确定删除"+cks.length+"条商品吗?")){ //拼接ID $.each(cks,function () { id=$(this).val(); //22 33 //非空判断,防止出错 if(id!=null) str += id+","; //22,33,44 }); //发送ajax请求 $.ajax({ url:"${pageContext.request.contextPath}/prod/deleteBatch.action", data:{"ids":str}, type:"post", dataType: "text", success:function (msg) { alert(msg); $("#table").load("http://localhost:8080/admin/product.jsp #table"); } }); } } }

14.2 在mapper中添加操作语句(复杂操作)
delete from product_info where p_id in /* 采用foreach来拼接多个数据 * collection="array" 数组类型 * separator="," 每个数值之间的间隔符 * open="(" 开始的字符 * close=")" 结束的字符 */ #{pid}

14.3 实现删除
@Override public int deleteBatch(String[] ids) { return productInfoMapper.deleteBatch(ids); }

//ajax异步批量删除 @ResponseBody @RequestMapping(value = "https://www.it610.com/deleteBatch",produces = "text/html; charset=UTF-8") public Object delete(String ids,HttpSession session){ //将上传的id拼接字符串拆分为字符数组 String[] pids = ids.split(","); //num受影响行数 int num=0; try { num = productInfoService.deleteBatch(pids); } catch (Exception e) { e.printStackTrace(); }//重新分页 PageInfo info = productInfoService.splitPage(1,PAGE_SIZE); session.setAttribute("info",info); if(num>0){ return "批量删除成功!"; }else{ return"批量删除失败!"; }}

    推荐阅读