『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)

ssm知识学习见SSM_面向CRUD编程专栏

本项目来自动力节点的【米米商城】

博主对于该知识尚在学习阶段

如果发现存在问题请毫不吝啬的指出

扎哇太枣糕的博客主页

项目完成并更新到giteeZaoGao_ssm: ssm项目——枣糕商城 ,但是不建议使用仓库中gitee的前端页面,博客中会有相应的初始化的前端页面下载,从头跟着博客一步一步的做

目录

1 框架构建

1.1 项目所需技术

1.2 项目搭建

1.3 配置所有的文件信息

2 登录功能的业务逻辑 

2.1 MD5加密算法

2.2 登录代码

2.3 测试执行 

3 商品管理功能的业务逻辑 

3.1 商品管理之查询所有产品

3.2 商品管理之Ajax分页翻页显示

3.3 商品管理之新增商品

3.3.1 新增商品之下拉框显示商品类型

3.3.2 新增商品之异步Ajax图片上传

3.3.3 新增商品之信息持久化数据库

3.4 商品管理之商品编辑

 3.5 商品管理之商品删除

3.5.1 商品删除之单个删除

3.5.2 商品删除之批量删除

3.6 商品管理之多条件查询

3.6 商品管理之删除优化


1 框架构建

1.1 项目所需技术

  • 服务端:Spring+SpringMVC+MyBatis
  • 数据库:MySql
  • web服务器:Tomcat
  • 项目管理:Maven
  • 前端:jQuery+BootStrap+JavaScript+Ajax
  • 开发工具:idea

        其中前端页面、图片等部分提供源码,不需要我们自己进行编写,只需要了解即可。

1.2 项目搭建

第一步:创建一个maven项目

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第1张图片

第二步:添加web依赖成为web项目 

这里因为一些原因使用的是以前的图,本次项目需要在上步创建好的项目上右键,一通操作之后将生成的web目录放到src/main目录下

第三步:搭建层级结构,里面内容为空 『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第2张图片

第四步:导入所有的前端页面

        下载前端页面复制粘贴到web目录下,下载地址:枣糕商城所需的前端页面下载

第五步:创建数据库

        下载数据库的SQL文件,在Navicat的连接处右键运行SQL文件选中文件并运行,或者直接将下载好的文件拖拽到Navicat的连接处,SQL文件下载地址:枣糕商城的数据库SQL文件下载

第六步:pom.xml文件导入依赖

    
    
        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
    

    
        
        
            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}
        
        
        
            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
        


        
        
            jstl
            jstl
            ${jstl.version}
        
        
            javax.servlet
            javax.servlet-api
            3.0.1
            provided
        
        
            javax.servlet
            jsp-api
            provided
            ${jsp-api.version}
        
        
        
            com.fasterxml.jackson.core
            jackson-databind
            ${jackson.version}
        
        
            commons-io
            commons-io
            2.4
        
        
            commons-fileupload
            commons-fileupload
            1.3.1
        
    

    
    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    1.8
                    1.8
                    UTF-8
                
            
        
        
        
            
                src/main/java
                
                    **/*.properties
                    **/*.xml
                
                false
            
            
                src/main/resources
                
                    **/*.properties
                    **/*.xml
                
                false
            
        
    

1.3 配置所有的文件信息

配置文件先都创建好并加入一些基本配置信息,后期还会对其中内容进行增添

mybatis.xml

resource目录右键-->new-->File






    
        
    

jdbc.properties

resource目录右键-->new-->File

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/zaogaossm?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
jdbc.username=root
jdbc.password=123456

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第3张图片

spring-dao.xml

resource目录右键-->new-->XML Configuration File-->Spring Config




    
    

    
    
        
        
        
        
    

    
    
        
        
        
        
        
        
    

    
    
        
    

spring-service.xml

resource目录右键-->new-->XML Configuration File-->Spring Config




    
    
        
        
    

spring-tx.xml

resource目录右键-->new-->XML Configuration File-->Spring Config





    
    
    
        
    
    
    
    
        
            
            
            
            
            
            
            
            
            
            
            
            
        
    

    
    
        
        
    

springMVC.xml

resource目录右键-->new-->XML Configuration File-->Spring Config




    
    


    
    
        
    

    
    
        
        
    

    
    

web.xml

添加web支持之后生成的web/WEB-INF/web.xml




    
    
        /admin/login.jsp
    

    
    
        dispatcherServlet
        org.springframework.web.servlet.DispatcherServlet
        
        
            contextConfigLocation
            classpath:springMVC.xml
        
    
    
        dispatcherServlet
        *.action
    

    
    
        org.springframework.web.context.ContextLoaderListener
    
    
    
        contextConfigLocation
        classpath:spring-*.xml
    

    
    
        encode
        org.springframework.web.filter.CharacterEncodingFilter
        
            encoding
            UTF-8
        
        
            forceRequestEncoding
            true
        
        
            forceResponseEncoding
            true
        
    
    
        encode
        /*
    

2 登录功能的业务逻辑 

2.1 MD5加密算法

        MD5加密算法可以直接下载该java文件放到utils目录下即可使用,下载地址:实现MD5加密java文件下载 ,下载之后复制粘贴到utils目录下『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第4张图片         这里插播一个小内容,前面生成数据库表的sql文件有一点点的问题,在admin表中存储的数据是000000,实际上应该是c984aed014aec7623a54f0591da07a85fd4b762d, 即是000000经过MD5加密之后的字符串。所以我们要先改变一下a_pass这个字段的长度为255,在将加密之后的字符串存进去。『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第5张图片

2.2 登录代码

        按本人业务实现习惯都是先编写domain层的数据库对应实体类(有的话就不写),然后是mapper接口和对应的xml映射文件的编写,再然后就是service接口和对应实现类的编写,最后就是controller与前端交互的编写。编写顺序依照个人习惯而言,写着舒服即可。

domain层

admin数据表对应的实体类

public class Admin {
    private Integer aId;

    private String aName;

    private String aPass;

    public Integer getaId() {
        return aId;
    }

    public void setaId(Integer aId) {
        this.aId = aId;
    }

    public String getaName() {
        return aName;
    }

    public void setaName(String aName) {
        this.aName = aName == null ? null : aName.trim();
    }

    public String getaPass() {
        return aPass;
    }

    public void setaPass(String aPass) {
        this.aPass = aPass == null ? null : aPass.trim();
    }
}

mapper层

mapper接口实现按用户名查询数据库

public interface AdminMapper {

    /**
     * 管理员的登录
     * @param name 管理员的用户名
     * @return Admin
     * */
    List queryByName(String name);
}

        在resource目录下新建一个package使用com/xiaochen/mapper命名,这里的分割符一定是/而不是.具体为啥我也不知道,package中新建一个AdminMapper.xml文件





    
    
        
        
        
    

    
    

service层

AdminService接口

public interface AdminService {
    /**
     * 管理员的登录
     * @param name 管理员的用户名
     * @return Admin
     * */
    List queryByName(String name);
}

创建一个AdminServiceImpl

@Service
public class AdminServiceImpl implements AdminService {
    // 创建mapper层的对象,注入
    @Autowired
    private AdminMapper adminMapper;

    @Override
    public List queryByName(String name) {
        // 调用mapper的queryByName方法,得到所有用户名为name的管理员信息
        return adminMapper.queryByName(name);
    }
}

controller层

AdminController实现登录判断

@Controller
@RequestMapping("/admin")
public class AdminController {
    // 注入adminservice对象
    @Autowired
    private AdminService adminService;

    // 实现登录判断并进行相应的跳转
    @RequestMapping("/login")
    public String login(String name, String pwd, HttpServletRequest request) {

        List admins = adminService.queryByName(name);
        // 对查询到的所有管理员进行密码比对 
        for (Admin admin : admins) {
            // 数据库中存储的是加密之后的密码,于是要将输入的密码进行加密之后再进行比较
            if (MD5Util.getMD5(pwd).equals(admin.getaPass())) {
                // 登陆成功,跳转admin.jsp页面并将这个admin对象传递给前端
                request.setAttribute("admin", admin);
                return "main";
            }
        }
        // 所有的管理员密码都不匹配的话登陆失败,跳回login.jsp页面并传递失败信息
        request.setAttribute("errmsg", "用户名或者密码不正确!!");
        return "login";
    }
}

2.3 测试执行 

        tomcat版本安装(切记,不要安装tomcat 9!!如果安装tomcat9的话会导致下一步的商品管理显示不出来,本人使用的是tomcat 7.0.108仅供参考)以及idea中配置tomcat参考我的这篇博客,点击链接直接在目录上点击Tomcat的部分直接空降即可:关于黑马程序员最全SSM框架教程视频,P37集老师跳过的模块创建以及tomcat下载安装配置和运行等诸多问题

如果运行不开的话,自查一下以下两小项

依赖jar包是否已经导入到lib目录下

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第6张图片

web.xml文件是否加载上且正确加载

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第7张图片

一切就绪之后运行tomcat服务器会弹出登录界面(因为之前web.xml文件设置了标签,所以一启动就会跳转到这个登录的jsp页面)

 登陆成功,网页跳转

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第8张图片

登陆失败,回写数据

3 商品管理功能的业务逻辑 

3.1 商品管理之查询所有产品

 domain层

productInfo数据表对应的实体类

public class ProductInfo {
    private Integer pId;
    private String pName;
    private String pContent;
    private Integer pPrice;
    private String pImage;
    private Integer pNumber;
    private Integer typeId;
    private Date pDate;

    public Integer getpId() {
        return pId;
    }
    public void setpId(Integer pId) {
        this.pId = pId;
    }
    public String getpName() {
        return pName;
    }
    public void setpName(String pName) {
        this.pName = pName == null ? null : pName.trim();
    }
    public String getpContent() {
        return pContent;
    }
    public void setpContent(String pContent) {
        this.pContent = pContent == null ? null : pContent.trim();
    }
    public Integer getpPrice() {
        return pPrice;
    }
    public void setpPrice(Integer pPrice) {
        this.pPrice = pPrice;
    }
    public String getpImage() {
        return pImage;
    }
    public void setpImage(String pImage) {
        this.pImage = pImage == null ? null : pImage.trim();
    }
    public Integer getpNumber() {
        return pNumber;
    }
    public void setpNumber(Integer pNumber) {
        this.pNumber = pNumber;
    }
    public Integer getTypeId() {
        return typeId;
    }
    public void setTypeId(Integer typeId) {
        this.typeId = typeId;
    }
    public Date getpDate() {
        return pDate;
    }
    public void setpDate(Date pDate) {
        this.pDate = pDate;
    }
}

mapper层

ProductInfoMapper接口

public interface ProductInfoMapper {

    /**
     * 全部商品的显示
     * @return ProductInfo
     */
    List queryAll();
}

        在resource目录的com/xiaochen/mapper的package中新建一个ProductInfoMapper.xml文件





    
    
        
        
        
        
        
        
        
        
    

    
    

service层

ProductInfoService接口

public interface ProductInfoService {

    /**
     * 全部商品的显示
     * @return ProductInfo
     */
    List queryAll();
}

创建一个ProductInfoServiceImpl

@Service
public class ProductInfoServiceImpl implements ProductInfoService {
    // 注入productInfoMapper
    @Autowired
    private ProductInfoMapper productInfoMapper;

    @Override
    public List queryAll() {
        return productInfoMapper.queryAll();
    }
}

controller层

ProductInfoController查询所有的商品信息

@Controller
@RequestMapping("/prod")
public class ProductInfoController {

    // 注入productInfoService
    @Autowired
    private ProductInfoService productInfoService;

    // 查询所有的产品信息
    @RequestMapping("/queryAll")
    public String queryAll(HttpServletRequest request) {
        List products= productInfoService.queryAll();
        request.setAttribute("list", products);
        return "product";
    }

}

运行测试

        运行之前先修改一下前端页面mian.jsp和product.jsp的一个小小的代码,这个地方不是说前端代码有错只是本次测试使用,下面的功能还是要再改回来滴

 运行,切记是tomcat7,9的高版本会有问题 『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第9张图片

3.2 商品管理之Ajax分页翻页显示

        为了便于观察后面添加商品,也是符合实际场景,让数据库中的产品信息按照主键p_id倒序查出,这样的话新插入的数据就是在第一条显示了,这个功能交由MyBatis的查询解决。

  domain层

productInfo数据表对应的实体类,已经存在不再创建

mapper层

ProductInfoMapper接口添加方法

/**
* 对某表按某字段某顺序排序
* @param tableName 某表
* @param field 某字段
* @param order 某顺序desc降序或者abs升序
*/
List orderById(@Param("tableName") String tableName, @Param("field") String field, @Param("order") String order);

        在resource目录的com/xiaochen/mapper的package中的ProductInfoMapper.xml文件添加动态SQL查询语句

    
    

service层

ProductInfoService接口添加分页方法

    /**
     * 分页操作
     * @param pageNum 查询第几页的数据
     * @param PageSize 每页有几条数据
     * @return 分页插件中带的pageInfo实体类
     */
    PageInfo splitPage(int pageNum, int PageSize);

        ProductInfoServiceImpl添加分页方法,先调用倒序查询再将结果封装到分页插件自带的pageInfo实体类中,封装进去之后分页插件自动将查询到的集合转换成诸如一共可以分多少页上一页下一页等属性,然后就可以很简单的调用实体类中的属性完成分页翻页操作了

    @Override
    public PageInfo splitPage(int pageNum, int PageSize) {
        // 分页插件使用pageHelper进行分页设置
        PageHelper.startPage(pageNum, PageSize);
        // 调用orderById方法,对product_info表的p_id字段进行desc降序操作
        List productInfos = productInfoMapper.orderById("product_info", "p_id", "desc");
        // 将查询到的集合封装到pageInfo对象中并返回
        PageInfo pageInfo = new PageInfo<>(productInfos);
        return pageInfo;
    }

controller层

ProductInfoController进行分页用于返回展示一开始的五条数据,翻页是调用Ajax的翻页,翻页的技术前端已经完成,我们只需要编写翻页代码,将前端传回来的第几页查出来并返回给前端进行显示

首先需要在ProductInfoController类的最上面定义一个常量PAGE_SIZE值为5『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第10张图片

然后添加split方法

    // Ajax分页
    @RequestMapping("/split")
    public String split(HttpServletRequest request) {
        PageInfo pageInfo = productInfoService.splitPage(1, PAGE_SIZE);
        // 放到域中,前端接收
        request.setAttribute("info", pageInfo);
        return "product";
    }

    // Ajax翻页
    @ResponseBody
    @RequestMapping("/ajaxsplit")
    public void ajaxSplit(int page, HttpSession session) {
        PageInfo pageInfo = productInfoService.splitPage(page, PAGE_SIZE);
        // 放到域中,前端接收
        session.setAttribute("info", pageInfo);
    }

运行测试

        运行之前先将前端页面mian.jsp和product.jsp的代码修改回来,一个加上info.一个改成split.action

 运行,切记是tomcat7,9的高版本会有问题 

3.3 商品管理之新增商品

3.3.1 新增商品之下拉框显示商品类型

  domain层

productType数据表对应的实体类

public class ProductType {
    private Integer typeId;

    private String typeName;

    public Integer getTypeId() {
        return typeId;
    }

    public void setTypeId(Integer typeId) {
        this.typeId = typeId;
    }

    public String getTypeName() {
        return typeName;
    }

    public void setTypeName(String typeName) {
        this.typeName = typeName == null ? null : typeName.trim();
    }
}

mapper层

新建ProductTypeMapper接口

public interface ProductTypeMapper {

    /**
     * 查询所有的商品类别
     * @return ProductType
     */
    List queryAll();
}

        在resource目录的com/xiaochen/mapper的package中新建ProductTypeMapper.xml文件





    
    
        
        
    

    
    

service层

ProductTypeService接口

public interface ProductTypeService {

    /**
     * 查询所有的商品类别
     * @return ProductType
     */
    List queryAll();
}

ProductTypeServiceImpl实现类

// 注解加字符串为了监听器中创建对象使用
@Service("productTypeServiceImpl")
public class ProductTypeServiceImpl implements ProductTypeService {

    // 注入ProductTypeMapper对象
    @Autowired
    private ProductTypeMapper productTypeMapper;

    @Override
    public List queryAll() {
        List productTypes = productTypeMapper.queryAll();
        return productTypes;
    }
}

新建一个listener层

ProductTypeListener是一个监听器类,用于在web项目启动的时候获取所有的商品类别,并放到全局应用作用域中,供新增、修改、查询提供全部商品类型集合

@WebListener
public class ProductTypeListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        // 手工从spring容器取出ProductTypeServiceImpl的对象
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-*.xml");
        ProductTypeService productTypeService = (ProductTypeService) context.getBean("productTypeServiceImpl");
        // 获取所有的商品类别,并放到全局应用作用域中,供新增、修改、查询提供全部商品类型集合
        List productTypes = productTypeService.queryAll();
        servletContextEvent.getServletContext().setAttribute("ptlist", productTypes);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}

运行测试

         直接运行,切记是tomcat7,9的高版本会有问题 

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第11张图片

3.3.2 新增商品之异步Ajax图片上传

        下载随机生成文件名称的工具类,并将其复制粘贴到utils包下,下载地址:随机生成文件名的工具类下载使用UUID生成文件名,再拼接上图片的后缀,给图片随机生成一个新的名称,这么做的目的是新添加进去的图片不会因为命名相同而被覆盖掉

pom.xml文件添加依赖


    org.json
    json
    20140107

controller层

        ProductInfoController类中添加异步上传方法,主要就是将选择的图片重新生成一个新的名字转存在项目的webapp下的image_big文件夹下,并将封面图片的路径封装在一个JSON类型数据中,前端获取到JSON得到文件路径取出图片在前端进行一个回显的操作

// 异步Ajax上传
@ResponseBody
@RequestMapping("/ajaxImg")
public Object ajaxImg(MultipartFile pimage, HttpServletRequest request) throws IOException {

    // 提取生成文件名:UUID+上传文件的后缀
    String saveFileName = FileNameUtil.getUUIDFileName() + FileNameUtil.getFileType(pimage.getOriginalFilename());
    // 得到项目中图片存储的路径
    String path = request.getServletContext().getRealPath("/image_big");
    // 转存图片                  image_big的路径    动态分隔符    新生成的文件名
    pimage.transferTo(new File(path + File.separator + saveFileName));
    // 返回客户端JSON对象,封面图片的路径,为了在页面进行回显操作
    JSONObject object = new JSONObject();
    object.put("imgurl", saveFileName);

    return object.toString();
}

运行测试

直接运行,切记是tomcat7,9的高版本会有问题 

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第12张图片

3.3.3 新增商品之信息持久化数据库

  domain层

productInfo数据表对应的实体类已经存在不用创建

mapper层

ProductInfoMapper接口添加方法

/**
 * 新增商品信息持久化数据库
 * @param info 产品信息的数据库
 * @return 是否insert成功
 */
int save(ProductInfo info);

        在resource目录的com/xiaochen/mapper的package中的ProductInfoMapper.xml文件,添加插入数据的SQL



    insert into product_info(p_name,p_content,p_price,p_image,p_number,type_id,p_date) values (#{pName},#{pContent},#{pPrice},#{pImage},#{pNumber},#{typeId},#{pDate})

service层

ProductInfoService接口添加方法

/**
 * 新增商品信息持久化数据库
 * @param info 产品信息的数据库
 * @return 是否insert成功
 */
int save(ProductInfo info);

ProductInfoServiceImpl实现类

@Override
public int save(ProductInfo info) {
    int flag = productInfoMapper.save(info);
    return flag;
}

controller层

ProductInfoController将添加商品的所有信息持久化到数据库中

        为了方便获取图片名称,现将ProductInfoController类的ajaxImg方法中的方法变量saveFileName提升为类的成员变量,这样的话就可以在ProductInfoController类的所有方法中调用变量的值。具体操作是在常量PAGE_SIZE的下面定义变量saveFileName

并将ajaxImg方法中的String定义删去,相当于在类中定义并初始化,在方法中重新赋值

ProductInfoController类中添加save方法

// 持久化数据库
@RequestMapping("/save")
public String save(ProductInfo info, HttpServletRequest request) {

    // 前端已经获取到新增商品的商品名称、商品介绍、定价、总数量、类别
    // 后端添加图片名称和添加日期
    info.setpImage(saveFileName);
    info.setpDate(new Date());

    // 调用插入数据的方法,并返回msg给前台弹窗使用
    int flag = -1;
    try {
        flag = productInfoService.save(info);
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (flag > 0) {
        request.setAttribute("msg", "增加成功!!");
    }else {
        request.setAttribute("msg", "增加失败");
    }
    // 清空saveFileName里的值,为了下次增加或者修改的异步Ajax图片上传
    saveFileName = "";
    // 插入成功之后跳转执行上面的展示产品
    return "forward:/prod/split.action";
}

运行测试

        直接运行,切记是tomcat7,9的高版本会有问题 

3.4 商品管理之商品编辑

        商品编辑有两个需求,需求一:就是需要先根据主键p_id查询到所有的商品信息,交给前端做一个回显的操作。需求二:将前端页面中的数据更新到数据库(p_date不做更改),回显到前端页面的数据在数据库按照主键p_id进行一个更新操作

   domain层

productInfo数据表对应的实体类已经存在不用创建

mapper层

ProductInfoMapper接口添加方法

/**
 * 按主键p_id查询所有的数据
 * @param pid 商品的主键
 * @return 一个使用实体类封装好的商品所有信息
 */
ProductInfo queryById(int pid);

/**
 * 更新商品信息
 * @param info 使用实体类封装好的商品所有信息
 * @return 是否更新成功
 */
int update(ProductInfo info);

        在resource目录的com/xiaochen/mapper的package中的ProductInfoMapper.xml文件,添加插入数据的SQL






     update product_info set p_name=#{pName},p_content=#{pContent},p_price=#{pPrice},p_image=#{pImage},p_number=#{pNumber},type_id=#{typeId} WHERE p_id=#{pId}

service层

ProductInfoService接口添加方法

/**
 * 按主键p_id查询所有的数据
 * @param pid 商品的主键
 * @return 一个使用实体类封装好的商品所有信息
 */
ProductInfo queryById(int pid);

/**
 * 更新商品信息
 * @param info 使用实体类封装好的商品所有信息
 * @return 是否更新成功
 */
int update(ProductInfo info);

ProductInfoServiceImpl实现类

@Override
public ProductInfo queryById(int pid) {
    ProductInfo productInfo = productInfoMapper.queryById(pid);
    return productInfo;
}

@Override
public int update(ProductInfo info) {
    int flag = productInfoMapper.update(info);
    return flag;
}

controller层

ProductInfoController实现两个需求

// 根据主键查找商品,并传递给前端做一个回显的操作(点击编辑文本框里是该商品在数据库中的信息)
@RequestMapping("/one")
public String one(int pid, Model model) {
    ProductInfo info = productInfoService.queryById(pid);
    model.addAttribute("prod", info);
    return "update";
}

// 更新商品信息
@RequestMapping("update")
public String update(ProductInfo info, HttpServletRequest request) {
    // 判断一下,如果点击编辑之后不去更新图片的话,saveFileName就是空的,此时图片使用的是前端隐藏域信息,图片的名称从前端域中获取并回显
    // 反之,点击浏览修改图片信息的话,相当于又是一次的Ajax异步上传,这时就会使用UUID生成一个新的图片名saveFileName
    // 需要我们手动将图片的名设置为saveFileName
    if (!saveFileName.equals("")) {
        info.setpImage(saveFileName);
    }
    // 数据库更新
    int num = -1;
    try {
        num = productInfoService.update(info);
    } catch (Exception e) {
        e.printStackTrace();
    }
    // 返回msg信息给前端弹窗使用
    if (num > 0) {
        request.setAttribute("msg", "更新成功!");
    }else {
        request.setAttribute("msg", "更新失败!");
    }
    //清空saveFileName,不影响下一次操作
    saveFileName = "";
    // 插入成功之后跳转执行上面的展示产品
    return "forward:/prod/split.action";
}

运行测试

        首先修改一下前端update.jsp第119行左右的一个代码

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第13张图片

        直接运行,切记是tomcat7,9的高版本会有问题 

 3.5 商品管理之商品删除

3.5.1 商品删除之单个删除

        页面上的商品删除工作有一个需求,就是在第几页删除之后还是返回还是在第几页,只不过需要用到查询的内容,于是先让其返回第一页,最后再优化实现同页返回。

domain层

productInfo数据表对应的实体类已经存在不用创建

mapper层

ProductInfoMapper接口添加方法

/**
 * 按照主键对商品进行删除
 * @param pid 商品的主键
 * @return 是否删除成功
 */
int delete(int pid);

        在resource目录的com/xiaochen/mapper的package中的ProductInfoMapper.xml文件,添加插入数据的SQL



    delete from product_info where p_id=#{pid}

service层

ProductInfoService接口添加方法

/**
 * 按照主键对商品进行删除
 * @param pid 商品的主键
 * @return 是否删除成功
 */
int delete(int pid);

ProductInfoServiceImpl实现类

@Override
public int delete(int pid) {
    int flag = productInfoMapper.delete(pid);
    return flag;
}

controller层

ProductInfoController实现两个需求

// 更新商品信息
@RequestMapping("/delete")
public String delete(int pid, HttpServletRequest request) {
    // 删除数据
    int flag = -1;
    try {
        flag = productInfoService.delete(pid);
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (flag > 0) {
        request.setAttribute("msg", "删除成功!!");
    }else {
        request.setAttribute("msg", "删除失败!!");
    }
    // 删除成功之后跳转执行上面的展示产品
    return "forward:/prod/deleteAjaxSplit.action";
}

// 返回弹窗的msg信息
@ResponseBody
@RequestMapping(value = "/deleteAjaxSplit", produces = "text/html;charset=UTF-8")
public Object deleteAjaxSplit(HttpServletRequest request) {
    // 取得第一页的数据
    PageInfo info = productInfoService.splitPage(1, PAGE_SIZE);
    request.getSession().setAttribute("info", info);
    // 返回msg语句
    return request.getAttribute("msg");
}

运行测试

        首先修改一下前端product.jsp的两处代码

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第14张图片

$.ajax({
   url:"${pageContext.request.contextPath}/prod/delete.action",
   data:{"pid":pid},
   type:"post",
   dataType:"text",
   success:function (msg) {
       alert(msg);
       $("#table").load("${pageContext.request.contextPath}/admin/product.jsp #table");
   }
});

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第15张图片

        直接运行,切记是tomcat7,9的高版本会有问题 

3.5.2 商品删除之批量删除

domain层

productInfo数据表对应的实体类已经存在不用创建

mapper层

ProductInfoMapper接口添加方法

/**
 * 批量删除商品
 * @param ids 删除商品的主键p_id们
 * @return 是否删除成功
 */
int deleteBatch(String[] ids);

        在resource目录的com/xiaochen/mapper的package中的ProductInfoMapper.xml文件,添加插入数据的SQL



    delete from product_info
    
        
            #{pid}
        
    

service层

ProductInfoService接口添加方法

/**
 * 批量删除商品
 * @param ids 删除商品的主键p_id们
 * @return 是否删除成功
 */
int deleteBatch(String[] ids);

ProductInfoServiceImpl实现类

@Override
public int deleteBatch(String[] ids) {
    int flag = productInfoMapper.deleteBatch(ids);
    return flag;
}

controller层

ProductInfoController实现两个需求

// 批量删除商品
@RequestMapping("/deleteBatch")
public String deleteBatch(String pids, HttpServletRequest request) {

    // 分隔传过来的字符串,拆分为数组
    String[] ps = pids.split(",");
    // 批量删除并返回msg信息
    int flag = productInfoService.deleteBatch(ps);
    try {
        if (flag > 0) {
            request.setAttribute("msg", "批量删除成功!!");
        }else {
            request.setAttribute("msg", "批量删除成功!!");
        }
    } catch (Exception e) {
        request.setAttribute("msg", "商品不可删除!!");
    }
    return "forward:/prod/deleteAjaxSplit.action";
}

运行测试

        首先修改一下前端product.jsp的一处代码

function deleteBatch() {
    //取得所有被选中删除商品的pid
    var cks=$("input[name=ck]:checked");
    if(cks.length==0){
        alert("请先选择将要删除的商品!!");
    }else{
        var str="";
        var pid="";
        // 有选中的商品,则取出每个选 中商品的ID,拼提交的ID的数据
        if(confirm("您确定删除这"+cks.length+"条商品吗?")){
        //拼接ID
            $.each(cks,function () {

                pid=$(this).val(); //22 33

                if(pid!=null) {
                    str += pid + ",";  //22,33,44
                }
            });

            //发送ajax请求进行批量删除
            $.ajax({
                url:"${pageContext.request.contextPath}/prod/deleteBatch.action",
                data:{"pids":str},
                type:"post",
                dataType:"text",
                success:function (msg) {
                    alert(msg);
                    // 重新刷新div块的内容
                    $("#table").load("${pageContext.request.contextPath}/admin/product.jsp #table");
                }
            });
        }
     }

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第16张图片        直接运行,切记是tomcat7,9的高版本会有问题 

3.6 商品管理之多条件查询

domain层

domain包下创建一个vo包,vo包下创建一个ProductInfoVo类,用于封装查询条件

public class ProductInfoVo {

    // 商品名称
    private String pname;
    // 商品类型
    private Integer typeid;
    // 最低价格
    private Integer lprice;
    // 最高价格
    private Integer hprice;
    // 设置页码
    private Integer page = 1;

    public ProductInfoVo() {
    }

    public ProductInfoVo(String pname, Integer typeid, Integer lprice, Integer hprice, Integer page) {
        this.pname = pname;
        this.typeid = typeid;
        this.lprice = lprice;
        this.hprice = hprice;
        this.page = page;
    }

    public String getPname() {
        return pname;
    }

    public void setPname(String pname) {
        this.pname = pname;
    }

    public Integer getTypeid() {
        return typeid;
    }

    public void setTypeid(Integer typeid) {
        this.typeid = typeid;
    }

    public Integer getLprice() {
        return lprice;
    }

    public void setLprice(Integer lprice) {
        this.lprice = lprice;
    }

    public Integer getHprice() {
        return hprice;
    }

    public void setHprice(Integer hprice) {
        this.hprice = hprice;
    }

    public Integer getPage() {
        return page;
    }

    public void setPage(Integer page) {
        this.page = page;
    }
}

mapper层

ProductInfoMapper接口添加方法

/**
 * 多条件查询
 * @param vo 所有条件的封装
 * @return 返回所有的商品信息
 */
List queryByCondition(ProductInfoVo vo);

        在resource目录的com/xiaochen/mapper的package中的ProductInfoMapper.xml文件,添加插入数据的SQL


service层

ProductInfoService接口添加方法

/**
 * 多条件查询
 * @param vo 所有条件的封装
 * @return 返回所有的商品信息
 */
List queryByCondition(ProductInfoVo vo);

/**
 * 多条件查询分页
 * @param vo 查询条件
 * @param pageSize 每页有几条数据
 * @return
 */
PageInfo splitPageVo(ProductInfoVo vo, int pageSize);

ProductInfoServiceImpl实现类

@Override
public List queryByCondition(ProductInfoVo vo) {
    List productInfos = productInfoMapper.queryByCondition(vo);
    return productInfos;
}

@Override
public PageInfo splitPageVo(ProductInfoVo vo, int pageSize) {
    // 分页插件使用pageHelper进行分页设置
    PageHelper.startPage(vo.getPage(), pageSize);
    // 调用orderById方法,对product_info表的p_id字段进行desc降序操作
    List productInfos = productInfoMapper.queryByCondition(vo);
    // 将查询到的集合封装到pageInfo对象中并返回
    PageInfo pageInfo = new PageInfo<>(productInfos);
    return pageInfo;
}

controller层

 ProductInfoController修改上面的split方法,调用分页时判断是有条件还是无条件的

// Ajax分页
@RequestMapping("/split")
public String split(HttpServletRequest request) {
    PageInfo pageInfo = null;
    // 获取条件封装类vo
    ProductInfoVo prodVo = (ProductInfoVo) request.getSession().getAttribute("prodVo");
    // 判断vo中是否有条件
    if (prodVo != null) {
        // 如果有条件的话就调用带条件的分页方法splitPageVo显示条件页面的数据
        pageInfo = productInfoService.splitPageVo(prodVo, PAGE_SIZE);
        // 从session中清除prodVo,以防对后面的操作有影响
        request.getSession().removeAttribute("prodVo");
    }else {
        // 如果没有条件的话就调用不带条件的分页方法splitPage显示第一页面的数据
        pageInfo = productInfoService.splitPage(1, PAGE_SIZE);
    }
    // 放到域中,前端接收
    request.setAttribute("info", pageInfo);
    return "product";
}

ProductInfoController修改上面的one方法,更新之后能够停留在当前页面

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第17张图片

 ProductInfoController修改上面的ajaxSplit方法,翻页的时候获取页码,停留到vo当前页,如果vo没值的话就是第一页

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第18张图片

// 批量删除商品
@RequestMapping("/deleteBatch")
public String deleteBatch(String pids, HttpServletRequest request) {

    // 分隔传过来的字符串,拆分为数组
    String[] ps = pids.split(",");
    // 批量删除并返回msg信息
    int flag = productInfoService.deleteBatch(ps);
    try {
        if (flag > 0) {
            request.setAttribute("msg", "批量删除成功!!");
        }else {
            request.setAttribute("msg", "批量删除成功!!");
        }
    } catch (Exception e) {
        request.setAttribute("msg", "商品不可删除!!");
    }
    return "forward:/prod/deleteAjaxSplit.action";
}

运行测试

        首先修改一下前端product.jsp的四处代码

function one(pid, page) {
    // 取出查询条件
    var pname = $("#pname").val();
    var typeid = $("#typeid").val();
    var lprice = $("#lprice").val();
    var hprice = $("#hprice").val();
    //拼接查询条件
    var str = "?pid=" + pid + "&page=" + page + "&pname=" + pname + "&typeid=" + typeid + "&lprice=" + lprice + "&hprice=" + hprice;
    location.href = "${pageContext.request.contextPath}/prod/one.action" + str;
}

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第19张图片

function ajaxsplit(page) {
    // 取出查询条件
    var pname = $("#pname").val();
    var typeid = $("#typeid").val();
    var lprice = $("#lprice").val();
    var hprice = $("#hprice").val();
    //异步ajax分页请求
    $.ajax({
    url:"${pageContext.request.contextPath}/prod/ajaxsplit.action",
        data:{"page":page, "pname":pname, "typeid":typeid, "lprice":lprice, "hprice":hprice},
        type:"post",
        success:function () {
            //重新加载分页显示的组件table
            //location.href---->http://localhost:8080/admin/login.action
            $("#table").load("http://localhost:8080/admin/product.jsp #table");
        }
    });
}

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第20张图片

function condition() {
    var pname = $("#pname").val();
    var typeid = $("#typeid").val();
    var lprice = $("#lprice").val();
    var hprice = $("#hprice").val();

    $.ajax({
        type:"post",
        url:"${pageContext.request.contextPath}/prod/ajaxsplit.action",
        data:{"pname":pname, "typeid":typeid, "lprice":lprice, "hprice":hprice},
        success:function () {
            // 刷新显示table的div
            $("#table").load("${pageContext.request.contextPath}/admin/product.jsp #table");
        }
    });
}

       直接运行,切记是tomcat7,9的高版本会有问题 

        这部分就不再给大家演示了,可以自己操作测试,完成的成果是:在上面的查询时能按照所填的条件查询出相应的商品,更新后依旧停留在当前页面

3.6 商品管理之删除优化

前端代码修改『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第21张图片

//单个删除
function del(pid, page) {
    // 弹窗提示
    if (confirm("确定删除吗")) {
      // 发送异步Ajax请求,进行删除操作
        // 取出查询条件
        var pname = $("#pname").val();
        var typeid = $("#typeid").val();
        var lprice = $("#lprice").val();
        var hprice = $("#hprice").val();
        $.ajax({
           url:"${pageContext.request.contextPath}/prod/delete.action",
           data:{"pid":pid, "page":page, "pname":pname, "typeid":typeid, "lprice":lprice, "hprice":hprice},
           type:"post",
           dataType:"text",
           success:function (msg) {
               alert(msg);
               $("#table").load("${pageContext.request.contextPath}/admin/product.jsp #table");
           }
        });
    }
}

后端 ProductInfoController『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第22张图片

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第23张图片

// 返回弹窗的msg信息
@ResponseBody
@RequestMapping(value = "/deleteAjaxSplit", produces = "text/html;charset=UTF-8")
public Object deleteAjaxSplit(HttpServletRequest request) {
    // 取得第一页的数据
    PageInfo info = null;
    // 获取条件封装类vo
    ProductInfoVo deleteProdVo = (ProductInfoVo) request.getSession().getAttribute("deleteProdVo");
    // 判断vo中是否有条件
    if (deleteProdVo != null) {
        // 如果有条件的话就调用带条件的分页方法splitPageVo显示条件页面的数据
        info = productInfoService.splitPageVo(deleteProdVo, PAGE_SIZE);
    }else {
        // 如果没有条件的话就调用不带条件的分页方法splitPage显示第一页面的数据
        info = productInfoService.splitPage(1, PAGE_SIZE);
    }
    request.getSession().setAttribute("info", info);
    // 返回msg语句
    return request.getAttribute("msg");
}

至此,枣糕商城ssm项目已经算是告一段落了,但是项目本身还存在一些小问题和未开发的模块,敬请大家期待完善

『收藏向 期末SSM课设救急』 教你从搭建到测试运行手撸一个SSM项目实战,附带源码,前端页面、解析和一般遇到的问题(排雷)_第24张图片

你可能感兴趣的:(SSM框架_面向CRUD编程,课程设计,p2p,ssm,后端,开发语言)