阶段总结——SSM商城实战项目

小米商城

技术栈Java SSM

技术选型 版本
数据库 MySQL 8.0.18
JDK 1.8.0
Spring 5.2.1
Spring MVC 5.2.1
mybatis 3.2.4
mysql-connector-java 8.0.18
dbcp/c3p0/druid c3p0

功能

  1. 基本的用户登录以及注册功能,用户注册或登录后会自动跳转页面;
  2. 首页数据加载,由于拿到的页面是一个空架子,因此需要自己对首页的数据加载功能进行编写与完善,可以实现在首页加载出商品名称以及商品图片;
  3. 首页商品类型的展示,在首页侧边栏添加商品类型的展示,并对展示的商品类型进行数据填充;
  4. 首页商品搜索功能,用户可以在首页进行商品的搜索;
  5. 根据类型检索商品,用户可以点击侧边栏的商品类型,从而检索出自己想要查看的商品类型;
  6. 商品详情的展示,当用户点击对应的商品的时候,页面便会跳转到商品详情页进行商品详情的展示;
  7. 商品加入购物车功能,用户可以将商品加入到购物车,但是用户必须登录才能进行此操作;
  8. 用户将商品加入购物车后可以点击购物车查看自己已经选择加入购物车的商品;
  9. (说明:这个小项目实现的功能比较少,自己后来也改动了很多不足之处,而且因为时间问题还有很多功能没有添加,由于本人也刚学完SSM框架没多久,因此编写的代码多多少少会有不足之处,今后会逐一改善,果然自己不动手写项目就永远不知道自己有多菜>_<)

1. 数据分析

商城项目:(小米商城:Business -to- Customer B2C)
用户:收货地址、用户扩展资料…
商品:商品图片,商品类型,商品套餐,售后服务…
元素都可以抽象成实体类型,就是对应了数据库中的表格。

2. mybatis逆向工程

逆向工程,就是通过数据库中已经存在的数据表,反向生成Java中的实体类(生成对应的ORM持久层代码)

(1) 创建商城项目

代码生成器作为商城项目的一个工具组件存在。
我们这里使用maven构建项目,便于管理jar包。
引入逆向工程依赖:

  1. mysql-connector-java-8.0.18.jar
  2. mybatis-generator-core-1.4.0.jar
    (我们可以到https://mvnrepository.com去搜索相关依赖)
 	   <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>8.0.18</version>
       </dependency>

       <!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
       <dependency>
           <groupId>org.mybatis.generator</groupId>
           <artifactId>mybatis-generator-core</artifactId>
           <version>1.4.0</version>
       </dependency>

(2) 配置生成规则

逆向工程的生成规则,就是描述数据库中的哪些表,生成对应的Java实体类,同时生成映射配置文件,这个生成规则就是一个普通的配置文件。
在项目的主目录中创建一个配置文件:/generator.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>

    <context id="DB2Tables" targetRuntime="MyBatis3">
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/xiaomi?serverTimezone=PRC"
                        userId="root"
                        password="Root2019">
        </jdbcConnection>

        <javaTypeResolver >
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <javaModelGenerator targetPackage="com.damu.xiaomi.entry"
                            targetProject="./src/main/java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <sqlMapGenerator targetPackage="mapper"
                         targetProject="./src/main/resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>

        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.damu.xiaomi.dao"
                             targetProject="./src/main/java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>

        <table tableName="consumer" domainObjectName="Consumer"></table>
        <table tableName="goods" domainObjectName="Goods"></table>
        <table tableName="goods_images" domainObjectName="GoodsImages"></table>
        <table tableName="goods_type" domainObjectName="GoodsType"></table>
        <table tableName="goods_service" domainObjectName="GoodsService"></table>
        <table tableName="goods_package" domainObjectName="GoodsPackage"></table>
        <table tableName="goods_configure" domainObjectName="GoodsConfigure"></table>
        <table tableName="goods_cart" domainObjectName="GoodsCart"></table>
        <table tableName="goods_order" domainObjectName="GoodsOrder"></table>
        <table tableName="goods_order_item" domainObjectName="GoodsOrderItem"></table>
        <table tableName="goods_shipping_address" domainObjectName="GoodsShippingAddress"></table>


    </context>
</generatorConfiguration>

(3) 逆向工程

通过配置文件指定的生成规则,自动构建实体类和数据访问类,我们可以参考官方文档来编写。

package com.damu.xiaomi.utils;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class CodeGenerator {
    
    

    public static void main(String[] args) throws Exception {
    
    
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        File configFile = new File("generator.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
    }
}

3. SSM项目整合

(1) 配置文件整合

Spring配置文件:src/main/resources/applicaationContext.xml
SpringMVC配置文件:src/main/resources/SpringMVC.xml
mybatis配置文件:src/main/resources/mybatis-config.xml
数据源配置文件:src/main/resources/db.properties
项目启动时,框架初始化,需要在web.xml中添加启动配置。
在项目中创建对应的空的配置文件,同时给项目添加web支持。
web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
		  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <!--<context-param>
        <param-name>log4jConfiguration</param-name>
        <param-value>classpath:log4j2.xml</param-value>
    </context-param>
    &lt;!&ndash; Log4j的监听器要放在spring监听器前面 &ndash;&gt;
    <listener>
        <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
    </listener>
    <filter>
        <filter-name>log4jServletFilter</filter-name>
        <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>log4jServletFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>ERROR</dispatcher>
    </filter-mapping>-->
    <!-- 1. spring 启动监听器-->
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>


    <!-- 2. spring MVC 前端控制器配置 -->
    <servlet>
        <servlet-name>springDispacherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springDispacherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!-- 3. 配置编码过滤,spring4以后需要配置请求/响应编码 -->
    <filter>
        <filter-name>characterEncoding</filter-name>
        <filter-class>
            org.springframework.web.filter.CharacterEncodingFilter
        </filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 4. 使用REST风格的uri,将页面中普通的POST请求转换成delete/put请求 -->
    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

(2) 依赖添加

  1. spring-core
  2. spring-context
  3. spring-beans
  4. spring-expression
  5. sping-jdbc
  6. spring-orm
  7. spring-web
  8. spring-webmvc
  9. mybatis
  10. mybatis-spring
  11. c3p0
       <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-core</artifactId>
           <version>5.2.1.RELEASE</version>
       </dependency>

       <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-beans</artifactId>
           <version>5.2.1.RELEASE</version>
       </dependency>

       <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-context</artifactId>
           <version>5.2.1.RELEASE</version>
       </dependency>

       <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-expression</artifactId>
           <version>5.2.1.RELEASE</version>
       </dependency>

       <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-jdbc</artifactId>
           <version>5.2.1.RELEASE</version>
       </dependency>
       <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-orm</artifactId>
           <version>5.2.1.RELEASE</version>
       </dependency>

       <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-web</artifactId>
           <version>5.2.1.RELEASE</version>
       </dependency>

       <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-webmvc</artifactId>
           <version>5.2.1.RELEASE</version>
       </dependency>

       <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
       <dependency>
           <groupId>org.mybatis</groupId>
           <artifactId>mybatis</artifactId>
           <version>3.5.3</version>
       </dependency>

       <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
       <dependency>
           <groupId>org.mybatis</groupId>
           <artifactId>mybatis-spring</artifactId>
           <version>2.0.3</version>
       </dependency>

       <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
       <dependency>
           <groupId>com.mchange</groupId>
           <artifactId>c3p0</artifactId>
           <version>0.9.5.4</version>
       </dependency>

(3) 细化配置文件

针对配置文件中的配置信息进行处理,可以参考官方文档进行配置
applicaationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.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">

    <!-- 1.自动扫描配置 -->
    <context:component-scan base-package="com.damu">
        <!-- Spring不扫描控制器 -->
        <context:exclude-filter type="annotation"
                                expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- 2. 引入数据源配置 -->
    <context:property-placeholder location="classpath*:db.properties" />

    <!-- 数据源配置:c3p0 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!-- 数据库驱动 -->
        <property name="driverClass" value="${jdbc.driver}" />
        <!-- 数据库连接串 -->
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}" />
        <!-- 数据库用户 -->
        <property name="user" value="${jdbc.user}" />
        <!-- 数据库密码 -->
        <property name="password" value="${jdbc.password}" />
        <!-- 最小连接数 -->
        <property name="minPoolSize" value="${jdbc.minPoolSize}" />
        <!-- 最大连接数 -->
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}" />
        <!-- 最大空闲的时间,单位是秒,无用的链接再过时后会被回收 -->
        <property name="maxIdleTime" value="${jdbc.maxIdleTime}" />
        <!-- 数据库连接池初始化时获取的连接数  -->
        <property name="initialPoolSize" value="${jdbc.initialPoolSize}" />
        <!-- 在当前连接数耗尽的时候,一次获取的新的连接数 -->
        <property name="acquireIncrement" value="${jdbc.acquireIncrement}" />
        <!-- 每隔1800S检查数据库空闲连接 -->
        <property name="idleConnectionTestPeriod"
                  value="${jdbc.idleConnectionTestPeriod}" />
        <!-- 当数据库连接失败以后尝试 重新连接的次数 -->
        <property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}" />
    </bean>

    <!-- 3. 配置mybatis整合-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- mybatis全局配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml">
        </property>
        <!-- 配置数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 配置扫描mapper -->
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>

    <!-- 配置扫描器:将mybatis接口实现加入到ioc容器中 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 扫描所有的dao接口的实现,加入到ioc容器中 -->
        <property name="basePackage" value="com.damu.xiaomi.dao"/>
    </bean>

    <!-- 4. 事务控制 -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 开启注解支持的事务控制,比较重要的使用配置实现 -->
    <aop:config>
        <!-- 配置切入点 -->
        <aop:pointcut expression="execution(* com.damu.xiaomi.service..*(..))" id="txPoint"/>
        <!-- 配置事务增强 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
    </aop:config>
    <!-- 配置事务增强 -->
    <tx:advice id="txAdvice">
        <tx:attributes>
            <!-- 所有方法都是事务方法-->
            <tx:method name="*" />
            <!-- 所有get开头的方法,配置优化 -->
            <tx:method name="get*" read-only="true"/>
        </tx:attributes>
    </tx:advice>


</beans>

springMVC.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://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">

    <!-- 1. 扫描所有容器组件 -->
    <context:component-scan base-package="com.damu" use-default-filters="false">
        <!-- 只扫描controller-->
        <context:include-filter type="annotation"
                                expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- 2. 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!-- 3. 两个标准配置:将springMVC不能处理的请求交给默认处理器处理[tomcat]-->
    <mvc:default-servlet-handler />

    <!-- 添加注解支持、映射动态请求、JSR303校验、快捷AJAX等 -->
    <mvc:annotation-driven/>

</beans>

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置 -->
    <settings>
        <!-- 配置驼峰命名规则 -->
        <setting name="mapUnderscoreToCamelCase" value="true" />
        <!-- 配置日志记录实现 -->
        <!--<setting name="logImpl" value="LOG4J2" />-->
    </settings>
    <!-- 别名 -->
    <typeAliases>
        <package name="com.damu.entry"/>
    </typeAliases>
</configuration>

db.properties

jdbc.jdbcUrl=jdbc:mysql://localhost:3306/xiaomi?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.user=root
jdbc.password=Root2019
jdbc.minPoolSize=10
jdbc.maxPoolSize=20
jdbc.maxIdleTime=1800
jdbc.initialPoolSize=2
jdbc.acquireIncrement=2
jdbc.idleConnectionTestPeriod=1800
jdbc.acquireRetryAttempts=2

4. 单元测试

(1) 引入依赖

		<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.1.RELEASE</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>

(2) 单元测试代码

package com.damu.test;

import com.damu.xiaomi.dao.ConsumerMapper;
import com.damu.xiaomi.entry.Consumer;
import com.damu.xiaomi.entry.ConsumerExample;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;
//这是一个要加载Spring容器的测试
@RunWith(SpringJUnit4ClassRunner.class)
//加载Spring的配置文件
@ContextConfiguration(locations = {
    
    "classpath:applicationContext.xml"})
public class DaoTest {
    
    
    @Autowired
    private ConsumerMapper consumerMapper;
    
    @Test
    public void testConsumerInsert() {
    
    
        // 创建consumer对象
        Consumer consumer = new Consumer("xiaozhang", "123");
        // 将consumer对象增加到数据库中
        consumerMapper.insertSelective(consumer);
        System.out.println("数据insert执行完成");
    }

    @Test
    public void testConsumerSelectById() {
    
    
        Consumer consumer = consumerMapper.selectByPrimaryKey(1);
        System.out.println(consumer);
    }

    @Test
    public void testConsumerSelectByExample() {
    
    
        // 创建一个查询条件【账号+密码】
        ConsumerExample ce = new ConsumerExample();
        ce.createCriteria().andUsernameEqualTo("xiaozhang").andPasswordEqualTo("123");
        // 查询数据
        List<Consumer> consumers = consumerMapper.selectByExample(ce);
        consumers.forEach(consumer-> System.out.println(consumer));
    }
}

5. 业务模型开发和响应封装

从简单业务模型处理–>复杂业务模型操作(注册,登录)–>首页数据加载–>搜索–>购物车–>订单

(1) 登录业务

首先创建用户相关业务处理类

package com.damu.xiaomi.service;

import com.damu.xiaomi.dao.ConsumerMapper;
import com.damu.xiaomi.entry.Consumer;
import com.damu.xiaomi.entry.ConsumerExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ConsumerService {
    
    
    @Autowired
    private ConsumerMapper consumerMapper;

    public boolean findConsumerWithUsernameAndPassword(Consumer consumer) {
    
    

        // 创建一个条件对象
        ConsumerExample ce = new ConsumerExample();
        ce.createCriteria().andUsernameEqualTo(consumer.getUsername()).andPasswordEqualTo(consumer.getPassword());
        // 查询数据
        List<Consumer> consumerList = consumerMapper.selectByExample(ce);
        // 判断返回结果
        return consumerList != null && consumerList.size() == 1;

    }
}

其次创建用户相关业务访问接口/控制器

package com.damu.xiaomi.controller;

import com.damu.xiaomi.entry.Consumer;
import com.damu.xiaomi.service.ConsumerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/consumer")
public class ConsumerController {
    
    
    @Autowired
    private ConsumerService consumerService;

    @PostMapping(value="/login/auth", produces = {
    
    "application/json;charset=UTF-8"})
    @ResponseBody // 序列化--> 类型转换--> jackson --> json
    public ResponseMessage login(@RequestParam String username, @RequestParam String password) {
    
    
        System.out.println("接受到请求:/consumer/login/auth");
        System.out.println("账号:" + username + "; 密码:" + password);
        Consumer consumer = new Consumer(username, password);
        boolean result = consumerService.findConsumerWithUsernameAndPassword(consumer);
        System.out.println("登录结果:" + result);
        return result ? "success" : "error";
    }
}

基于web业务的单元测试

package com.damu.test;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    
    "classpath:applicationContext.xml", "classpath:springMVC.xml"})
@WebAppConfiguration
public class WebTest {
    
    

    // 声明一个模拟请求的对象
    private MockMvc mockMvc;
    // 需要一个web容器
    @Autowired
    private WebApplicationContext context;

    @Before
    public void setUp() {
    
    
        mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }

    @Test
    public void testLogin() throws Exception {
    
    
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/consumer/login/auth").param("username", "xiaozhang").param("password", "123")).andReturn();
 		System.out.println(mvcResult.getResponse().getContentAsString());
    }
}

(2) 响应数据封装

关于数据接口,提供给用户端调用,并且返回符合标准预期的数据访问接口,通常会有如下的要求

  1. 固定格式的参数,根据需求提供给调用接口即可
  2. 返回数据-错误码:快捷判断响应结果是否正确的错误标志,如HTTP:200正确;404资源未找到;500错误
  3. 返回数据-错误描述:针对某错误码具体错误信息的描述
  4. 返回数据-数据封装:具体包含的一个或者多个数据
    在项目中定义工具类型,封装响应数据
package com.damu.xiaomi.utils;

import java.util.HashMap;
import java.util.Map;

public class ResponseMessage {
    
    
    private String errorCode;
    private String errorMsg;
    private Map<String, Object> objectMap = new HashMap<>();

    public String getErrorCode() {
    
    
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
    
    
        this.errorCode = errorCode;
    }

    public String getErrorMsg() {
    
    
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
    
    
        this.errorMsg = errorMsg;
    }

    public Map<String, Object> getObjectMap() {
    
    
        return objectMap;
    }

    public void setObjectMap(Map<String, Object> objectMap) {
    
    
        this.objectMap = objectMap;
    }

    public ResponseMessage addObject(String key, Object value) {
    
    
        this.objectMap.put(key, value);
        return this;
    }

    public static ResponseMessage success() {
    
    
        ResponseMessage rm = new ResponseMessage();
        rm.setErrorCode("100");
        rm.setErrorMsg("处理成功");
        return rm;
    }

    public static ResponseMessage error() {
    
    
        ResponseMessage rm = new ResponseMessage();
        rm.setErrorCode("200");
        rm.setErrorMsg("处理失败");
        return rm;
    }
}

重构登陆业务

 @PostMapping(value="/login/auth", produces = {
    
    "application/json;charset=UTF-8"})
 @ResponseBody // 序列化--> 类型转换--> jackson --> json
    public ResponseMessage login(@RequestParam String username,@RequestParam String password) {
    
    
        /*
        重构:登录业务
            1. 验证账号+密码
            2. 登记用户 -- 会话跟踪【session】
         */
        System.out.println("接受到请求:/consumer/login/auth");
        System.out.println("账号:" + username + "; 密码:" + password);
        Consumer consumer = new Consumer(username, password);
        consumer = consumerService.findConsumerWithUsernameAndPassword(consumer);
        System.out.println("登录结果:" + consumer);
        return consumer != null ? ResponseMessage.success() : ResponseMessage.error();
    }

6. 登录

对登录页面进行改动

<script src="js/jquery/jquery-3.4.1.js"></script>
    <script>
        $(function() {
     
     
           // 点击登录按钮时,发送ajax请求
           $("#login-btn").click(function() {
     
     
               // 发送ajax请求
               $.ajax({
     
     
                   url: "/xiaomi/consumer/login/auth",
                   method: "post",
                   data: {
     
     
                       "username": $("#username").val(),
                       "password": $("#password").val()
                   },
                   success:function(response) {
     
     
                       console.log("请求发送成功");
                       console.log(response);
                       if(response.errorCode === "100") {
     
     
                           // 登录成功
                           alert("恭喜,用户登录成功!");
                           window.location = "/xiaomi/index.jsp";
                       } else {
     
     
                           // 登录失败
                           $("#error-username").text("账号或者密码有误,请重新登录").css({
     
     "color": "red"});
                       }
                   },
                   error: function() {
     
     
                       console.log("请求发送失败..");

                   }
               });
           });
        });
    </script>

7. 用户注册

在ConsumerService中添加注册方法

public String register(Consumer consumer) {
    
    
        // 验证用户的账号是否存在
        ConsumerExample ce = new ConsumerExample();
        ce.createCriteria().andUsernameEqualTo(consumer.getUsername());
        // 根据条件对象查询数据
        List<Consumer> consumerList = consumerMapper.selectByExample(ce);
        if (consumerList != null && consumerList.size() > 0) {
    
    
            return "注册失败,账号已经存在,请使用其他账号注册";
        }
        // 添加用户
        consumerMapper.insertSelective(consumer);
        return "注册成功";
    }

在控制层ConsumerController中添加注册方法

@PostMapping("/register")
    @ResponseBody
    public ResponseMessage register(@RequestParam String username, @RequestParam String password) {
    
    
        // 创建用户对象
        Consumer consumer = new Consumer(username, password);
        // 注册用户
        String result = consumerService.register(consumer);

        // 判断结果
        if (result.contains("注册成功")) {
    
    
            return ResponseMessage.success();
        }
        return ResponseMessage.error().addObject("msg", result);
    }

网页视图及功能完善

<script src="js/jquery/jquery-3.4.1.js"></script>
    <script>
        $(function() {
     
     
            // 点击注册按钮时,发送请求
            $("#register-btn").click(function() {
     
     
                // 发送Ajax请求
                $.ajax({
     
     
                    url: "/xiaomi/consumer/register",
                    method: "POST",
                    data: {
     
     
                        "username": $("#username").val(),
                        "password": $("#password").val()
                    },
                    success: function(response) {
     
     
                        if(response.errorCode === "100") {
     
     
                            alert("Congratulations,账号注册成功,请登录吧");
                            window.location = "/xiaomi/login.jsp";
                        }else{
     
     
                            $("#errorMsg").text(response.objectMap.msg).css({
     
     "color": "red"});
                        }
                    },
                    error: function() {
     
     
                        $("#errorMsg").text("请求迷路了,小二正在赶来的路上,请稍后再试..").css({
     
     "color": "red"});
                    }
                });
            });
        });
    </script>

8. 首页数据加载

首页中需要的数据,从后台获取并且添加

  1. 商品类型
  2. 每种类型下的商品

开发业务处理层
3. 商品类型:GoodsTypeService
4. 商品:GoodsShippingService

GoodsTypeService

package com.damu.xiaomi.service;

import com.damu.xiaomi.dao.GoodsTypeMapper;
import com.damu.xiaomi.entry.GoodsType;
import com.damu.xiaomi.entry.GoodsTypeExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class GoodsTypeService {
    
    

    @Autowired
    private GoodsTypeMapper goodsTypeMapper;

    /**
     * 查询一级商品类型
     * @return 返回所有的一级商品类型
     */
    public List<GoodsType> findTopLevel() {
    
    
        GoodsTypeExample gte = new GoodsTypeExample();
        gte.createCriteria().andPidIsNull();
        return goodsTypeMapper.selectByExample(gte);
    }

    /**
     * 根据一级类型,查询所有所属二级类型
     * @return 返回类型列表
     */
    public List<GoodsType> findSecondLevel(GoodsType top) {
    
    
        GoodsTypeExample gte = new GoodsTypeExample();
        gte.createCriteria().andPidEqualTo(top.getId());
        return goodsTypeMapper.selectByExample(gte);
    }
}

GoodsShippingService

package com.damu.xiaomi.service;

import com.damu.xiaomi.dao.GoodsMapper;
import com.damu.xiaomi.dao.GoodsTypeMapper;
import com.damu.xiaomi.entry.Goods;
import com.damu.xiaomi.entry.GoodsExample;
import com.damu.xiaomi.entry.GoodsType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class GoodsShippingService {
    
    
    @Autowired
    private GoodsMapper goodsMapper;
    @Autowired
    private GoodsTypeService goodsTypeService;

    /**
     * 根据id查询商品
     * @param id 商品编号
     * @return 返回查询到的商品
     */
    public Goods findGoodsWithId(Integer id) {
    
    
        return goodsMapper.selectByPrimaryKey(id);
    }
    /**
     * 根据商品类型查询商品
     * @param goodsType 二级商品类型
     * @return 属于指定商品类型的所有商品
     */
    public List<Goods> findGoodsWithType(GoodsType goodsType) {
    
    
        GoodsExample ge = new GoodsExample();
        ge.createCriteria().andGoodsTypeIdEqualTo(goodsType.getId());
        return goodsMapper.selectByExample(ge);
    }

    /**
     * 根据一级类型查询商品数据
     * @param goodstype 一级类型
     * @return 返回所有商品
     */
    public List<Goods> findGoodsWithToptype(GoodsType goodstype) {
    
    
        // 根据一级类型查询所有所属二级类型
        List<GoodsType> gt = goodsTypeService.findSecondLevel(goodstype);
        // 查询所有二级类型下的所有商品
        List<Goods> goodsList = new ArrayList<>();
        for (GoodsType goodsType : gt) {
    
    
            List<Goods> goods = this.findGoodsWithType(goodsType);
            goodsList.addAll(goods);
        }
        return goodsList;
    }

    /**
     * 根据名称模糊搜索商品数据
     * @param name 商品名称
     * @return 返回符合搜索条件的商品
     */
    public List<Goods> searchGoodsWithName(String name) {
    
    
        // 构建条件
        GoodsExample ge = new GoodsExample();
        ge.createCriteria().andNameLike("%" + name + "%");
        return goodsMapper.selectByExample(ge);
    }

}

首页数据加载完善
修改entry.goods

//商品对应的商品图片
private List<GoodsImages> goodsImages;
public List<GoodsImages> getGoodsImages() {
    
      return goodsImages; }
public void setGoodsImages(List<GoodsImages> goodsImages) {
    
      this.goodsImages = goodsImages; }

开发首页控制器:IndexController.java

package com.damu.xiaomi.controller;

import com.damu.xiaomi.entry.Goods;
import com.damu.xiaomi.entry.GoodsType;
import com.damu.xiaomi.service.GoodsShippingService;
import com.damu.xiaomi.service.GoodsTypeService;
import com.damu.xiaomi.utils.ResponseMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class IndexController {
    
    
    @Autowired
    private GoodsTypeService goodsTypeService;
    @Autowired
    private GoodsShippingService goodsShippingService;

    @GetMapping("/initIndex")
    @ResponseBody
    public ResponseMessage initIndex() {
    
    
        // 查询一级商品类型数据
        List<GoodsType> topLevel = goodsTypeService.findTopLevel();

        Map<Integer, List<Goods>> goodsMap = new HashMap<>();
        // 遍历查询每个一级类型下的二级类型,按照 二级类型:商品类型
        for (GoodsType goodsType: topLevel) {
    
    
            // 查询所属一级类型下的所有二级类型
            List<GoodsType> secondLevel = goodsTypeService.findSecondLevel(goodsType);
            // 查询每个二级类型下的商品
            for(GoodsType secondGoodsType: secondLevel) {
    
    
                // 查询商品
                List<Goods> goodsList = goodsShippingService.findGoodsWithType(secondGoodsType);
                // 存储数据
                goodsMap.put(secondGoodsType.getId(), goodsList);
            }
        }
        // 返回首页需要的数据
        return ResponseMessage.success().addObject("goodsTypeList", topLevel).addObject("goodsMap", goodsMap);
    }
}

开发首页视图/web/index.jsp渲染商品展示

<script src="js/jquery/jquery-3.4.1.js"></script>
<script>
    $(function() {
       // 直接发送请求获取数据
       $.ajax({
           url: "/xiaomi/initIndex",
           method: "GET",
           success: function(response) {
               console.log(response);
               // 获取到后台返回的一级商品类型数据
               let $goodsTypes = response.objectMap.goodsTypeList;
               // 遍历商品类型
               for(let i = 0; i < $goodsTypes.length; i++) {
                   // 创建对应的标签
                   let $li = $("<li>").attr("id", $goodsTypes[i].id).text($goodsTypes[i].name);
                   let $span = $("<span>").append($("<em>").addClass("glyphicon glyphicon-menu-right"));
                   $li.append($span);
                   // 将数据加载到网页中ul菜单中
                   $("#bannel-type > ul").append($li);
               }
               // 加载楼层商品
               // 获取小米手机商品
               let $xiaomiphonelist = response.objectMap.goodsMap["10001"];
               loadGoods($xiaomiphonelist, $("#xiaomiphone"));
               // 获取红米手机商品
               let $hongmiphonelist = response.objectMap.goodsMap["10002"];
               loadGoods($hongmiphonelist, $("#hongmiphone"));
               // 获取游戏手机商品
               let $gamephonelist = response.objectMap.goodsMap["10003"];
               loadGoods($gamephonelist, $("#gamephone"));
               // 获取电视商品
               let $tvlist = response.objectMap.goodsMap["20002"];
               loadGoods($tvlist, $("#tv"));

           },
           error: function() {
               console.log("请求迷路了....")
           }
       });

       function loadGoods(goodslist, container) {
           // 遍历商品列表,将商品添加到页面汇总
           for(let i = 0; i < goodslist.length; i++) {
               let $boxitem = $("<div>").addClass("goodsboxitem");
               let $a = $("<a>").attr("href", "/xiaomi/detail.jsp?gid=" + goodslist[i].id);
               let $content = $("<div>").addClass("content");

               let $thumb = $("<div>").addClass("thumb");
               let $img = $("<img>").attr("src", goodslist[i].goodsImages[0].path);
               $thumb.append($img);

               let $title = $("<div>").addClass("title").text(goodslist[i].name);
               let $desc = $("<div>").addClass("desc").text(goodslist[i].remark.substring(10));

               let $price = $("<div>").addClass("price");
               let $span = $("<span>").text(goodslist[i].price + "元");
               let $del = $("<del>").text(goodslist[i].price + "元");
               $price.append($span).append($del);

               $content.append($thumb).append($title).append($desc).append($price);
               $a.append($content);
               $boxitem.append($a);

               container.append($boxitem);
           }
       }
<script>

9. 商品搜索

基本的搜索功能,直接和数据库进行交互,通过sql语句完成商品数据的检索,但是企业项目中需要的搜索功能很少会直接和数据库进行交互,一般情况下会使用数据中间件框架elasticsearch

(1) 商品按名称模糊搜索

/**
     * 根据名称模糊搜索商品数据
     * @param name 商品名称
     * @return 返回符合搜索条件的商品
     */
    public List<Goods> searchGoodsWithName(String name) {
    
    
        // 构建条件
        GoodsExample ge = new GoodsExample();
        ge.createCriteria().andNameLike("%" + name + "%");
        return goodsMapper.selectByExample(ge);
    }

控制层UtilsController

package com.damu.xiaomi.controller;

import com.damu.xiaomi.entry.Goods;
import com.damu.xiaomi.entry.GoodsType;
import com.damu.xiaomi.service.GoodsShippingService;
import com.damu.xiaomi.service.GoodsTypeService;
import com.damu.xiaomi.utils.ResponseMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@Controller
@RequestMapping("/u")
public class UtilsController {
    
    
    @Autowired
    private GoodsShippingService goodsShippingService;
    @Autowired
    private GoodsTypeService goodsTypeService;

    @GetMapping("/search/{name}")
    @ResponseBody
    public ResponseMessage searchGoodsWithName(@PathVariable String name) {
    
    
        List<Goods> goodsList = goodsShippingService.searchGoodsWithName(name);
        return goodsList.size() > 0 ? ResponseMessage.success().addObject("goodsList", goodsList): ResponseMessage.error();
    }
}

单元测试

@Autowired
    private GoodsShippingService goodsShippingService;
    @Test
    public void testSearchGoods() {
    
    
        List<Goods> goodsList = goodsShippingService.searchGoodsWithName("小米");
        goodsList.forEach(goods -> System.out.println(goods));
    }

最后进行网页视图的开发就行了:/web/goodsList.jsp

<!-- 相应的搜索框 -->
<form action="#" id="search">  
	<input type="text">  
	<button></button> 
</form>

(2) 商品按类型检索

一级类型查看
首页导航–> 根据一级类型查看所有商品
二级类型查看
楼层商品–> 根据二级类型查看商品
业务层开发,添加方法

/**
     * 根据商品类型查询商品
     * @param goodsType 二级商品类型
     * @return 属于指定商品类型的所有商品
     */
    public List<Goods> findGoodsWithType(GoodsType goodsType) {
    
    
        GoodsExample ge = new GoodsExample();
        ge.createCriteria().andGoodsTypeIdEqualTo(goodsType.getId());
        return goodsMapper.selectByExample(ge);
    }

 /**
     * 根据一级类型查询商品数据
     * @param goodstype 一级类型
     * @return 返回所有商品
     */
    public List<Goods> findGoodsWithToptype(GoodsType goodstype) {
    
    
        // 根据一级类型查询所有所属二级类型
        List<GoodsType> gt = goodsTypeService.findSecondLevel(goodstype);
        // 查询所有二级类型下的所有商品
        List<Goods> goodsList = new ArrayList<>();
        for (GoodsType goodsType : gt) {
    
    
            List<Goods> goods = this.findGoodsWithType(goodsType);
            goodsList.addAll(goods);
        }
        return goodsList;
    }

控制层添加方法

/**
     * 根据类型查看商品
     * @param level 类型级别 1 一级类型 2 二级类型
     * @param goodsTypeId 类型编号
     * @return 返回响应数据
     */
    @GetMapping("/search/{level}/{goodsTypeId}")
    @ResponseBody
    public ResponseMessage searchGoodsWithType(@PathVariable String level,
                                               @PathVariable String goodsTypeId) {
    
    
        // 根据编号查询类型
        GoodsType goodsType = goodsTypeService.findById(Integer.parseInt(goodsTypeId));
        List<Goods> goodsList = null;
        // 判断类型级别
        if("1".equals(level)) {
    
    
            goodsList = goodsShippingService.findGoodsWithToptype(goodsType);
        } else if("2".equals(level)) {
    
    
            goodsList = goodsShippingService.findGoodsWithType(goodsType);
        }
        return goodsList != null && goodsList.size() > 0
                ? ResponseMessage.success().addObject("goodsList", goodsList)
                : ResponseMessage.error();
    }
}

视图处理:/web/goodslist2.jsp

  1. index.jsp导航发起
  2. 跳转到指定页面goodslist2.jsp
  3. 在商品列表页面中,获取查询参数,发送请求获取数据
<script src="js/jquery/jquery-3.4.1.js"></script>
<script>
    $(function() {
     
     
        // ?level=1&goodsTypeid=102
        // 1. 获取搜索关键词
        let $search = window.location.search.substring(1).split("&"); // [level=1, goodsTypeid=102]
        let $level = $search[0].split("=")[1]; // 1
        let $goodsTypeId = $search[1].split("=")[1]; // 102
        console.log($level, $goodsTypeId);
        // 2. Ajax请求,搜索商品
        $.ajax({
     
     
            url: "/xiaomi/u/search/" + $level + "/" +  parseInt($goodsTypeId),
            method: "GET",
            success: function(response) {
     
     
                console.log(response);
                // 展示搜索到的商品
                let $goodslist = response.objectMap.goodsList;
                loadGoods($goodslist, $("#search_goods_box"))
            },
            error: function() {
     
     
                console.log("搜索请求迷路了...");
            }
        });
        function loadGoods(goodslist, container) {
     
     
            // 遍历商品列表,将商品添加到页面汇总
            for(let i = 0; i < goodslist.length; i++) {
     
     
                let $boxitem = $("<div>").addClass("goodsboxitem");
                let $a = $("<a>").attr("href", "/xiaomi/detail.jsp?gid=" + goodslist[i].id);
                let $content = $("<div>").addClass("content");

                let $thumb = $("<div>").addClass("thumb");
                let $img = $("<img>").attr("src", goodslist[i].goodsImages[0].path);
                $thumb.append($img);
                let $thumbx = $("<div>").addClass("thumbnailx");
                let $img2 = $("<img>").attr("src", goodslist[i].goodsImages[1].path);
                $thumbx.append($img2);

                let $title = $("<div>").addClass("title").text(goodslist[i].name);
                let $desc = $("<div>").addClass("desc").text(goodslist[i].remark.substring(10));

                let $price = $("<div>").addClass("price");
                let $span = $("<span>").text(goodslist[i].price + "元");
                let $del = $("<del>").text(goodslist[i].price + "元");
                $price.append($span).append($del);

                $content.append($thumb).append($title).append($desc).append($price).append($thumbx);
                $a.append($content);
                $boxitem.append($a);
                container.append($boxitem);
            }
        }
    });
</script>

10. 商品详情

在GoodsShippingService中添加方法findGoodsWithId(…)

/**
     * 根据id查询商品
     * @param id 商品编号
     * @return 返回查询到的商品
     */
    public Goods findGoodsWithId(Integer id) {
    
    
        return goodsMapper.selectByPrimaryKey(id);
    }

商品详情控制器接口开发:GoodsController

package com.damu.xiaomi.controller;

import com.damu.xiaomi.entry.Goods;
import com.damu.xiaomi.service.GoodsShippingService;
import com.damu.xiaomi.utils.ResponseMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/goods")
public class GoodsController {
    
    
    @Autowired
    private GoodsShippingService goodsShippingService;

    @GetMapping("/detail/{gid}")
    @ResponseBody
    public ResponseMessage findGoodsWithId(@PathVariable Integer gid) {
    
    
        Goods goods = goodsShippingService.findGoodsWithId(gid);
        return ResponseMessage.success().addObject("goods", goods);
    }
}

最后进行网页视图处理即可,发送Ajax请求获取对应的商品信息

11. 购物车

商品加入购物车 detail.jsp 商品详情页 --> 加入购物车 --> 加入购物车流程
业务处理层:ShopCartService

package com.damu.xiaomi.service;

import com.damu.xiaomi.dao.GoodsCartMapper;
import com.damu.xiaomi.entry.Consumer;
import com.damu.xiaomi.entry.Goods;
import com.damu.xiaomi.entry.GoodsCart;
import com.damu.xiaomi.entry.GoodsCartExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

@Service
public class ShopCartService {
    
    
    @Autowired
    private GoodsCartMapper goodsCartMapper;

    /**
     * 指定商品加入购物车
     * @param goods 要加入购物车的商品
     * @return 返回加入结果
     */
    public boolean addGoodsToShopCart(Consumer consumer, Goods goods) {
    
    
        // 查询指定的商品在当前用户的购物车中是否存在
        List<GoodsCart> cartList = this.chkGoods(consumer, goods);
        if(cartList.size() > 0) {
    
    
            // 更新购买数量
            int count = cartList.get(0).getBuyCount();
            cartList.get(0).setBuyCount(count+1);
            // 更新小金额
            double price = cartList.get(0).getSubtotal()/count * cartList.get(0).getBuyCount();
            cartList.get(0).setSubtotal(price);
        } else {
    
    
            // 新增商品
            GoodsCart gc = new GoodsCart(goods.getId(), 1, new Date(), goods.getPrice(), consumer.getId());
            goodsCartMapper.insertSelective(gc);
        }
        return true;
    }

    /**
     * 从购物车中删除指定的商品
     * @param goods 要删除的商品
     * @return 返回删除结果
     */
    public boolean removeGoodsFromShopCart(Consumer consumer, Goods goods) {
    
    
        // 判断商品在购物车中是否存在
        List<GoodsCart> cartList = this.chkGoods(consumer, goods);
        if(cartList.size() > 0) {
    
    
            // 商品存在,删除
            goodsCartMapper.deleteByPrimaryKey(cartList.get(0).getId());
            return true;
        }
        System.out.println("商品不存在.");
        return false;
    }

    /**
     * 查询指定用户购物车中所有商品
     * @param consumer 指定用户
     * @return 返回该用户的所有商品
     */
    public List<GoodsCart> findAllGoodsCartWithConsumer(Consumer consumer) {
    
    
        GoodsCartExample gce = new GoodsCartExample();
        gce.createCriteria().andConsumerIdEqualTo(consumer.getId());
        return goodsCartMapper.selectByExample(gce);
    }

    /**
     * 判断某个商品在购物车中是否存在
     * @param consumer 所属用户
     * @param goods 商品对象
     * @return 商品数据
     */
    private List<GoodsCart> chkGoods(Consumer consumer, Goods goods) {
    
    
        // 查询指定的商品在当前用户的购物车中是否存在
        GoodsCartExample gce = new GoodsCartExample();
        gce.createCriteria().andConsumerIdEqualTo(consumer.getId())
                .andGoodsIdEqualTo(goods.getId());
        // 查询操作
        List<GoodsCart> cartList = goodsCartMapper.selectByExample(gce);
        return cartList;
    }
}

重构登录方法

 @Autowired
    private ConsumerService consumerService;

    @PostMapping(value="/login/auth", produces = {
    
    "application/json;charset=UTF-8"})
    @ResponseBody // 序列化--> 类型转换--> jackson --> json
    public ResponseMessage login(@RequestParam String username,
                                 @RequestParam String password,
                                 HttpSession session) {
    
    
        /*
        重构:登录业务
            1. 验证账号+密码
            2. 登记用户 -- 会话跟踪【session】
         */
        System.out.println("接受到请求:/consumer/login/auth");
        System.out.println("账号:" + username + "; 密码:" + password);
        Consumer consumer = new Consumer(username, password);
        consumer = consumerService.findConsumerWithUsernameAndPassword(consumer);
        System.out.println("登录结果:" + consumer);
        // 记录登录用户
        session.setAttribute("loginConsumer", consumer);
        return consumer != null ? ResponseMessage.success() : ResponseMessage.error();
    }

控制层ShopCartController

package com.damu.xiaomi.controller;

import com.damu.xiaomi.entry.Consumer;
import com.damu.xiaomi.entry.Goods;
import com.damu.xiaomi.entry.GoodsCart;
import com.damu.xiaomi.service.GoodsShippingService;
import com.damu.xiaomi.service.ShopCartService;
import com.damu.xiaomi.utils.ResponseMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpSession;
import java.util.List;

@Controller
@RequestMapping("/shopcart")
public class ShopCartController {
    
    
    @Autowired
    private ShopCartService shopCartService;
    @Autowired
    private GoodsShippingService goodsShippingService;

    @GetMapping("/add/{goodsId}")
    @ResponseBody
    public ResponseMessage addGoodsToCart(@PathVariable Integer goodsId, HttpSession session) {
    
    
        // 获取当前登录用户
        Consumer consumer = (Consumer) session.getAttribute("loginConsumer");
        if (consumer == null) {
    
    
            return ResponseMessage.error();
        }
        // 加入商品到购物车
        Goods goods = goodsShippingService.findGoodsWithId(goodsId);
        shopCartService.addGoodsToShopCart(consumer, goods);
        return ResponseMessage.success();
    }

    @GetMapping("/remove/{goodsId}")
    @ResponseBody
    public ResponseMessage removeGoodsFromCart(@PathVariable Integer goodsId, HttpSession session) {
    
    
        // 获取当前登录用户
        Consumer consumer = (Consumer) session.getAttribute("loginConsumer");
        if (consumer == null) {
    
    
            return ResponseMessage.error();
        }
        Goods goods = goodsShippingService.findGoodsWithId(goodsId);
        shopCartService.removeGoodsFromShopCart(consumer, goods);

        return ResponseMessage.success();
    }

    @GetMapping("/chk")
    @ResponseBody
    public ResponseMessage findAllWithConsumer(HttpSession session) {
    
    
        // 获取当前登录用户
        Consumer consumer = (Consumer) session.getAttribute("loginConsumer");
        if (consumer == null) {
    
    
            return ResponseMessage.error();
        }
        List<GoodsCart> cartList = shopCartService.findAllGoodsCartWithConsumer(consumer);
        return ResponseMessage.success().addObject("cartList", cartList);
    }
}

网页视图处理

  1. 添加商品到购物车操作:在详情页面完成
  2. 查看购物车商品:在购物车页面完成

猜你喜欢

转载自blog.csdn.net/ARSCCC/article/details/106491761
今日推荐