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项目(商城管理系统)-- 完整_第1张图片
这里通过手动添加web模块,这种通过手动添加web模块方式创建的web项目是非常纯净的,没有任何附加的代码,开发中推荐。也可以使用maven的模板(在创建Maven时选择模板)创建web项目

如下图所示,添加web模块
ssm项目(商城管理系统)-- 完整_第2张图片

ssm项目(商城管理系统)-- 完整_第3张图片

2. 配置 pom.xml文件

2.1 集中定义全局变量 : 依赖版本号 (方便管理版本)


<properties>
    <junit.version>4.12junit.version>  
    <spring.version>5.2.5.RELEASEspring.version>  
    <mybatis.version>3.5.1mybatis.version>  
    <mybatis.spring.version>1.3.1mybatis.spring.version>  
    <mybatis.paginator.version>1.2.15mybatis.paginator.version>  
    <mysql.version>8.0.22mysql.version>   
    <slf4j.version>1.6.4slf4j.version>  
    <druid.version>1.1.12druid.version>  
    <pagehelper.version>5.1.2pagehelper.version>  
    <jstl.version>1.2jstl.version>   
    <servlet-api.version>3.0.1servlet-api.version>   
    <jsp-api.version>2.0jsp-api.version>  
    <jackson.version>2.9.6jackson.version>  
properties>

2.2 依赖

... 中添加依赖

spring 所需要的依赖

    
    
         
<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-contextartifactId>
    <version>${spring.version}version>
dependency>

  
<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-beansartifactId>
    <version>${spring.version}version>
dependency>

  
<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-webmvcartifactId>
    <version>${spring.version}version>
dependency>

  
<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-jdbcartifactId>
    <version>${spring.version}version>
dependency>

  
<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-aspectsartifactId>
    <version>${spring.version}version>
dependency>

  
<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-jmsartifactId>
    <version>${spring.version}version>
dependency>

  
<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-context-supportartifactId>
    <version>${spring.version}version>
dependency>

  
<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-testartifactId>
    <version>${spring.version}version>
dependency>

Mybatis相关依赖

    

  
<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>${mybatis.version}version>
dependency>

  
<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatis-springartifactId>
    <version>${mybatis.spring.version}version>
dependency>

  
<dependency>
    <groupId>com.github.miemiedevgroupId>
    <artifactId>mybatis-paginatorartifactId>
    <version>${mybatis.paginator.version}version>
dependency>

  
<dependency>
    <groupId>com.github.pagehelpergroupId>
    <artifactId>pagehelperartifactId>
    <version>${pagehelper.version}version>
dependency>

数据库相关的依赖


<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>${mysql.version}version>
dependency>

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druidartifactId>
    <version>${druid.version}version>
dependency>

单元测试依赖


<dependency>
    <groupId>junitgroupId>
    <artifactId>junitartifactId>
    <version>${junit.version}version>
    <scope>testscope>
dependency>

JSP相关依赖


<dependency>
    <groupId>jstlgroupId>
    <artifactId>jstlartifactId>
    <version>${jstl.version}version>
dependency>
<dependency>
    <groupId>javax.servletgroupId>
    <artifactId>javax.servlet-apiartifactId>
    <version>3.0.1version>
    <scope>providedscope>
dependency>
<dependency>
    <groupId>javax.servletgroupId>
    <artifactId>jsp-apiartifactId>
    <scope>providedscope>
    <version>${jsp-api.version}version>
dependency>

ackson Json处理工具包

    
    <dependency>
        <groupId>com.fasterxml.jackson.coregroupId>
        <artifactId>jackson-databindartifactId>
        <version>${jackson.version}version>
    dependency>

文件异步上传

    <dependency>
        <groupId>commons-iogroupId>
        <artifactId>commons-ioartifactId>
        <version>2.4version>
    dependency>
    <dependency>
        <groupId>commons-fileuploadgroupId>
        <artifactId>commons-fileuploadartifactId>
        <version>1.3.1version>
    dependency>
dependencies>

2.3 插件

... 中添加插件

jdk 编译版本

<plugin>
    <groupId>org.apache.maven.pluginsgroupId>
    <artifactId>maven-compiler-pluginartifactId>
    <configuration>
        <source>1.8source>
        <target>1.8target>
        <encoding>UTF-8encoding>
    configuration>
plugin>

2.4 识别配置文件

... 中添加


<resources>
    <resource>
        <directory>src/main/javadirectory>
        <includes>
            <include>**/*.propertiesinclude>
            <include>**/*.xmlinclude>
        includes>
        <filtering>falsefiltering>
    resource>
    <resource>
        <directory>src/main/resourcesdirectory>
        <includes>
            <include>**/*.propertiesinclude>
            <include>**/*.xmlinclude>
        includes>
        <filtering>falsefiltering>
    resource>
resources>

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接管,所以配置分页即可


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
    plugins>
configuration>

3.3 Spring配置文件

对spring配置文件按照分层进行拆分

3.3.1 数据持久层 – applicationContext_dao.xml

其中实体类pojo和mapper文件夹未创建,后面通过mybatis逆向工程生成


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    
    <context:property-placeholder location="classpath:jdbc.properties"/>

    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    bean>

    
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">

        <property name="dataSource" ref="dataSource"/>


        <property name="configLocation" value="classpath:mybatis-config.xml"/>


        <property name="typeAliasesPackage" value="com.yanyu.pojo">property>
    bean>

    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.yanyu.mapper"/>
    bean>
beans>

3.3.2 业务逻辑层 – applicationContext_service.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

<context:component-scan base-package="com.yanyu.service"/>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource">property>
bean>

<tx:advice id="myadvice" transaction-manager="transactionManager">

    <tx:attributes>
         
        <tx:method name="*select*" read-only="true"/>
        <tx:method name="*find*" read-only="true"/>
        <tx:method name="*get*" read-only="true"/>
        <tx:method name="*search*" read-only="true"/>
        
        <tx:method name="*insert*" propagation="REQUIRED"/>
        <tx:method name="*add*" propagation="REQUIRED"/>
        <tx:method name="*delete*" propagation="REQUIRED"/>
        <tx:method name="*remove*" propagation="REQUIRED"/>
        <tx:method name="*clear*" propagation="REQUIRED"/>
        <tx:method name="*update*" propagation="REQUIRED"/>
        <tx:method name="*modify*" propagation="REQUIRED"/>
        <tx:method name="*change*" propagation="REQUIRED"/>
        <tx:method name="*set*" propagation="REQUIRED"/>
        
        <tx:method name="*" propagation="SUPPORTS"/>
        
    tx:attributes>
tx:advice>


<aop:config>

   <aop:pointcut id="mypointcut" expression="execution(* com.yanyu.service.*.*(..))"/>

    <aop:advisor advice-ref="myadvice" pointcut-ref="mypointcut"/>
aop:config>
beans>

3.4 springMVC配置文件springmvc.xml

springmvc.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

<context:component-scan base-package="com.yanyu.controller"/>

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/admin/">property>
    <property name="suffix" value=".jsp">property>
bean>

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

bean>



<mvc:annotation-driven>mvc:annotation-driven>

beans>

4. 设置web.xml文件

4.1 添加字符编码过滤器

注:字符编码过滤器需放在web.xml顶端


<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    
    <filter>
        <filter-name>encodefilter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
        
        <init-param>
            <param-name>encodingparam-name>
            <param-value>UTF-8param-value>
        init-param>
        
        <init-param>
            <param-name>forceRequestEncodingparam-name>
            <param-value>tureparam-value>
        init-param>
        
        <init-param>
            <param-name>forceResponseEncodingparam-name>
            <param-value>tureparam-value>
        init-param>
    filter>
    
    <filter-mapping>
        <filter-name>encodefilter-name>
        <url-pattern>/*url-pattern>
    filter-mapping>
    
    

    
web-app>

4.2 注册SpringMVC框架

    
    <servlet>
        <servlet-name>springmvcservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath:springmvc.xmlparam-value>
        init-param>
    servlet>
    
    <servlet-mapping>
        <servlet-name>springmvcservlet-name>
        <url-pattern>*.actionurl-pattern>
    servlet-mapping>

    

4.3 注册Spring框架

spring配置文件若在WEB-INF目录下,会自动加载,在其他位置要手动加载

加载多个文件时有两个方法
1. 逗号隔开 :classpath:applicationContext_dao.xml,classpath:applicationContext_service.xml
2. 使用通配符 :classpath:applicationContext_*.xml (代表以 applicationContext_ 为前缀以.xml为后缀的文件)

    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
    listener>
    
    
    <context-param>
        <param-name>contextConfigLocationparam-name>
        
        <param-value>classpath:applicationContext_*.xmlparam-value>
    context-param>

5. 使用Mabatis逆向工程生成pojo和mapper

5.1 导入逆向工程

逆向工程简称MBG,是一个专门为MyBatis框架使用者定制的代码生成器,可以快速的根据表生成对应的映射文件,接口,以及bean类。支持基本的增删改查,以及QBC风格的条件查询。但是表连接、存储过程等这些复杂sqI的定义需要我们手工编写

  • 官方文档地址http://www.mybatis.org/generator/
  • 官方工程地址 https://github.com/mybatis/generator/releases

ssm项目(商城管理系统)-- 完整_第4张图片

5.2 修改配置文件

在generatorConfig.xml中配置Mapper生成的详细信息,如下图:
ssm项目(商城管理系统)-- 完整_第5张图片
注意修改内容主要以下几点:

  1. 修改数据库连接的信息

    	
    	<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
    		connectionURL="jdbc:mysql://localhost:3306/mimissm?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true" 
    		userId="root"
    		password="root">
    	jdbcConnection>
    
  2. 指定数据库表 (生成那些数据库表对应的文件) – admin,product_info,product_type

     	
     	<table schema="" tableName="admin">table>
     	<table schema="" tableName="product_info">table>
     	<table schema="" tableName="product_type">table>
    
  3. 生成PO类的位置 – com.yanyu.pojo

    
    	<javaModelGenerator targetPackage="com.yanyu.pojo"
    		targetProject=".\src">
    		
    		<property name="enableSubPackages" value="false" />
    		
    		<property name="trimStrings" value="true" />
    	javaModelGenerator>
    
  4. mapper映射文件生成的位置 – com.yanyu.mapper

     
    	<sqlMapGenerator targetPackage="com.yanyu.mapper"
    		targetProject=".\src">
    		
    		<property name="enableSubPackages" value="false" />
    	sqlMapGenerator>
    
  5. mapper接口生成的位置

    
     	<javaClientGenerator type="XMLMAPPER"
     		targetPackage="com.yanyu.mapper"
     		targetProject=".\src">
     		
     		<property name="enableSubPackages" value="false" />
     	javaClientGenerator>
    

5.3 运行GeneratorSqlmap,生成pojo和mapper文件

ssm项目(商城管理系统)-- 完整_第6张图片

运行前删除src下同名目录,防止文件重叠

运行程序后,在设置的目录下生成对应文件
ssm项目(商城管理系统)-- 完整_第7张图片

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<mdBytes.length;i++){           //循环字节数组
                int temp;
                if(mdBytes[i]<0)                          //如果有小于0的字节,则转换为正数
                    temp =256+mdBytes[i];
                else
                    temp=mdBytes[i];
                if(temp<16)
                    hash+= "0";
                hash+=Integer.toString(temp,16);         //将字节转换为16进制后,转换为字符串
            }
            return hash;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }
}

测试

    @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<Admin> 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<ProductInfo> getAll();
}

8.2 业务逻辑层 – 创建ProductInfoServiceImpl,实现getAll

ProductInfoServiceImpl

package com.yanyu.service.impl;

import ...

@Service
public class ProductInfoServiceImpl implements ProductInfoService {
    //数据访问层对象
    @Autowired
    ProductInfoMapper productInfoMapper;

    @Override
    public List<ProductInfo> 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<ProductInfo> 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<ProductInfo> list = productInfoMapper.selectByExample(example);

    //将数据封装进PageInfo中,PageInfo自动对list进行分页
    PageInfo<ProductInfo> 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中进行分页

<div id="table">
    
    <c:choose>
        
        <c:when test="${info.list.size()!=0}">
                     
            <div id="top">
                <input type="checkbox" id="all" onclick="allClick()" style="margin-left: 50px">  全选
                <a href="${pageContext.request.contextPath}/admin/addproduct.jsp">
                         
                    <input type="button" class="btn btn-warning" id="btn1"
                           value="新增商品">
                a>
                
                <input type="button" class="btn btn-warning" id="btn1"
                       value="批量删除" onclick="deleteBatch()">
            div>
            
            <div id="middle">
                <table class="table table-bordered table-striped">
                    <tr>
                        <th>th>
                        <th>商品名th>
                        <th>商品介绍th>
                        <th>定价(元)th>
                        <th>商品图片th>
                        <th>商品数量th>
                        <th>操作th>
                    tr>
                    
                    <c:forEach items="${info.list}" var="p">
                        <tr>
                            <td valign="center" align="center"><input type="checkbox" name="ck" id="ck" value="${p.pId}" onclick="ckClick()">td>
                            <td>${p.pName}td>
                            <td>${p.pContent}td>
                            <td>${p.pPrice}td>
                            <td><img width="55px" height="45px"
                                     src="${pageContext.request.contextPath}/image_big/${p.pImage}">td>
                            <td>${p.pNumber}td>
                            
                            <td>
                                <button type="button" class="btn btn-info "
                                        onclick="one(${p.pId},${info.pageNum})">编辑
                                button>
                                <button type="button" class="btn btn-warning" id="mydel"
                                        onclick="del(${p.pId})">删除
                                button>
                            td>
                            
                        tr>
                    c:forEach>
                table>
                
                
                <div id="bottom">
                    <div>
                        <nav aria-label="..." style="text-align:center;">
                            <ul class="pagination">
                                
                                <li>
                                    <a href="javascript:ajaxsplit(${info.prePage})" aria-label="Previous">
                                        <span aria-hidden="true">«span>a>
                                        
                                 
                                li>
                                 
                                <c:forEach begin="1" end="${info.pages}" var="i">
                                    <c:if test="${info.pageNum==i}">
                                        <li>
                                               
                                            <a href="javascript:ajaxsplit(${i})"
                                               style="background-color: grey">${i}a>
                                        li>
                                    c:if>
                                    <c:if test="${info.pageNum!=i}">
                                        <li>
                                               
                                            <a href="javascript:ajaxsplit(${i})">${i}a>
                                        li>
                                    c:if>
                                c:forEach>
                                 
                                <li>
                          
                                    <a href="javascript:ajaxsplit(${info.nextPage})" aria-label="Next">
                                        <span aria-hidden="true">»span>a>
                                li>
                                 
                                <li style=" margin-left:150px;color: #0e90d2;height: 35px; line-height: 35px;">总共   <font style="color:orange;">${info.pages}font>        
                                     
                                    <c:if test="${info.pageNum!=0}">
                                        当前   <font style="color:orange;">${info.pageNum}font>              
                                    c:if>
                                     
                                    <c:if test="${info.pageNum==0}"> 当前   <font style="color:orange;">1font>              
                                    c:if>
                                li>
                            ul>
                        nav>
                    div>
                div>
            div>
        c:when>
        <c:otherwise>
            <div>
                <h2 style="width:1200px; text-align: center;color: orangered;margin-top: 100px">暂时没有符合条件的商品!h2>
            div>
        c:otherwise>
    c:choose>
div>

9.5 分页的AJAX实现


<script 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");
            }
        })
    };

script>

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<ProductType> getAll();
}

创建ProductTypeServiceImpl实现接口的所有类别数据方法getAll

package com.yanyu.service.impl;

import ...

@Service("ProductTypeServiceImpl")
public class ProductTypeServiceImpl implements ProductTypeService {
    //数据访问层对象
    @Autowired
    ProductTypeMapper productTypeMapper;

    @Override
    public List<ProductType> getAll() {
        return productTypeMapper.selectByExample(new ProductTypeExample());
    }

}

10.2 通过监听器自动查询并存入全局对象中

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<ProductType> typeList = productTypeService.getAll();

        //放入全局作用域中
        sce.getServletContext().setAttribute("typeList",typeList);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

10.3 前端下拉框显示类别

<tr>
	<td class="one">类别td>
	<td>
		<select name="typeId">
		    
			<c:forEach items="${typeList}" var="type">
				<option value="${type.typeId}">${type.typeName}option>
			c:forEach>
		select>
	td>
tr>

11. 上传文件 --ajax异步上传并回显 – springMVC组件

11.1 前端上传图片

文件选择

<tr>
	<td class="three">图片介绍td>
	
    <td> <br><div id="imgDiv" style="display:block; width: 40px; height: 50px;">div><br><br><br><br>
    
    <input type="file" id="pimage" name="pimage" onchange="fileChange()" >
        <span id="imgName" >span><br>

    td>

Ajax异步提交事件 – 采用ajaxfileupload.js文件(封装ajax异步上传的功能)

<!-- 引入ajaxfileupload.js-->
<script type="text/javascript" src="${pageContext.request.contextPath }/js/ajaxfileupload.js"></script>

<script type="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 = $("");
                //给img标签对象追加属性
                imgObj.attr("src","/image_big/"+obj.imgurl);
                imgObj.attr("width","100px");
                imgObj.attr("height","100px");
                //将图片img标签追加到imgDiv末尾
                $("#imgDiv").append(imgObj);
            },
            error: function (e)//服务器响应失败处理函数
            {
                alert(e.message);
            }
        });
    }
</script>

11.2 在ProductInfoAction中添加异步Ajax文件上传处理

Ajax文件上传处理并返回含图片位置的json对象用于回显图片

//异步Ajax文件上传处理
@ResponseBody
@RequestMapping("/ajaxImg")
//pimage与前台上传的name值一样
public Object ajaxImg(MultipartFile pimage,HttpServletRequest request){
    //生成文件名和后缀,通过FileNameUtil工具类将前台上传的文件名通过UUID重新生成,防止重复
    String uuidFileName = FileNameUtil.getUUIDFileName()+FileNameUtil.getFileType(pimage.getOriginalFilename());
    //存取路径  -- 完整的项目本地路径
    String path = request.getServletContext().getRealPath("/image_big");
    //存储  File.separator -> \
    try {
        pimage.transferTo(new File(path+File.separator+uuidFileName));
    } catch (IOException e) {
        e.printStackTrace();
    }

    //返回josn对象,包含图片路径,
    String s = "{\"imgurl\":\""+uuidFileName+"\"}";
    return s;
}

FileNameUtil工具类 – 用于UUID文件名防止重复

package com.yanyu.utils;

import java.util.UUID;

public class FileNameUtil {
	//根据UUID生成文件名
	public static String getUUIDFileName() {
		UUID uuid = UUID.randomUUID();
		return uuid.toString().replace("-", "");
	}
	//从请求头中提取文件名和类型
	public static String getRealFileName(String context) {
		// Content-Disposition: form-data; name="myfile"; filename="a_left.jpg"
		int index = context.lastIndexOf("=");
		String filename = context.substring(index + 2, context.length() - 1);
		return filename;
	}
	//根据给定的文件名和后缀截取文件名
	public static String getFileType(String fileName){
		//9527s.jpg
		int index = fileName.lastIndexOf(".");
		return fileName.substring(index);
	}
}

12 . 新增商品功能

12.1 业务逻辑层 – 实现新增商品

ProductInfoService接口添加save方法

    //新增商品
    int save(ProductInfo info);

ProductInfoServiceImpl实现类实现save

    @Override
    public int save(ProductInfo info) {

        return productInfoMapper.insert(info);
    }

12.2 界面控制层 – ProductInfoAtion中,添加save完成添加,返回初始页

    @RequestMapping("/save")
    public String save(ProductInfo info,HttpServletRequest request){
        //文件由ajaxImg方法上传,将uuidFileName设置为全局变量,在此传递给数据库
        info.setpImage(uuidFileName);
        //前端提交的数据不包含时间,由后端添加
        info.setpDate(new Date());

        //num受影响行数
        int num=0;
        try {
            num = productInfoService.save(info);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(num>0){
            request.setAttribute("msg","增加成功!");
        }else{
            request.setAttribute("msg","增加失败!");
        }
        //转发到所有商品初始页
        return "forward:/prod/split.action";
    }

13. 更新商品

13.1 根据主键id查询商品,用于修改数据 - getById方法

业务逻辑层 – ProductInfoService接口添加getById方法

    //按主键id查询商品
    ProductInfo getById(int pid);

业务逻辑层 – ProductInfoServiceImpl实现类实现getById

    @Override
    public ProductInfo getById(int pid) {
        return productInfoMapper.selectByPrimaryKey(pid);
    }

界面控制层 – ProductInfoAtion中,添加one方法完成查询,返回修改页

    @RequestMapping("one")
    public String one(int pid, Model model){
        ProductInfo byId = productInfoService.getById(pid);
        model.addAttribute("prod",byId);
        //更新时可以修改图片,防止数据冲突,清除uuidFileName
        uuidFileName="";
        return "update";
    }

13.3 前端点击编辑,跳转one方法根据主键id查询所要修改的数据,回显

function one(pid) {
    location.href = "${pageContext.request.contextPath}/prod/one.action?pid=" + pid;
}

....

<button type="button" class="btn btn-info " onclick="one(${p.pId})">编辑 </button>

13.3 更新前端页面 – 主要代码

//取消时返回初始页
<script type="text/javascript">
	function myclose(ispage) {		window.location="${pageContext.request.contextPath}/admin/product/split.action";
		//window.close();
	}
script>

<div id="table">
	<form action="${pageContext.request.contextPath}/prod/update.action" enctype="multipart/form-data" method="post" id="myform">
	    //修改根据id,所以要提交,但不修改用隐藏域
		<input type="hidden" value="${prod.pId}" name="pId">
		//用于判断是否重新上传图片
		<input type="hidden" value="${prod.pImage}" name="pImage">
		
		...
		商品名称
		商品介绍
		定价
		...

            //显示图片和异步上传
			<tr>
				<td class="one">图片介绍td>
				<td> <br><div id="imgDiv" style="display:block; width: 40px; height: 50px;"><img src="/image_big/${prod.pImage}" width="100px" height="100px" >div><br><br><br><br>
					<input type="file" id="pimage" name="pimage" onchange="fileChange()">
					<span id="imgName">span><br>
				td>
			tr>
			...
			总数量
			...
			//取出全局中的数据,与修改商品的类别id对比,selected="selected"表示选中
			<tr>
				<td class="one">类别td>
				<td>
					<select name="typeId">
						<c:forEach items="${typeList}" var="type">
							<option value="${type.typeId}"
									if test="${type.typeId==prod.typeId}">
										selected="selected"
									c:if>
							>${type.typeName}option>

						c:forEach>
					select>
				td>
			tr>
				<td>
					<input type="submit" value="提交" class="btn btn-success">
				td>
				<td>
					<input type="reset" value="取消" class="btn btn-default" onclick="myclose(1)">
				td>
			tr>
		table>
	form>
div>

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 id="deleteBatch">
    delete from product_info where p_id in
    /* 采用foreach来拼接多个数据
     * collection="array" 数组类型
     * separator="," 每个数值之间的间隔符
     * open="(" 开始的字符
     * close=")" 结束的字符
     */
    <foreach collection="array" item="pid" separator="," open="(" close=")">
      #{pid}
    foreach>
  delete>

14.3 实现删除

@Override
    public int deleteBatch(String[] ids) {
        return productInfoMapper.deleteBatch(ids);
    }
    //ajax异步批量删除
    @ResponseBody
    @RequestMapping(value = "/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  "批量删除失败!";
        }

    }

你可能感兴趣的:(ssm框架项目,--,商城管理系统,maven,spring,java)