SSM练手之小米商城-笔记

2、mybatis逆向工程

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

1、创建商城项目

代码生成器作为商城项目的一个工具组件存在。

maven项目

引入逆向工程依赖

  • mybatis-generator-core
  • mybatis-connector-java

            mysql
            mysql-connector-java
            8.0.19
        
        
            org.mybatis.generator
            mybatis-generator-core
            1.4.0
        

2、配置生成规则

逆向工程的生成规则,就是描述数据库中的那些表,生成对应的Java中的实体类,同时生成映射配置文件。这个生成规则就是一个普通的配置文件。

在项目的主目录中创建一个配置文件:generator.xml







    
        
        

        
            
        

        
            
            
        

        
            
        

        
            
        


        

3、逆向工程

通过配置文件指定的生成规则,自动构建实体类和数据访问类,参考官方文档

public class CodeGenerator {
    public static void main(String[] args) throws  Exception{
        List warnings = new ArrayList();
        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/applicationContext.xml

springMVC配置文件:src/main/resources/springMVC.xml

mybatis配置文件:src/main/rescources/mybatis-config.xml

数据源配置文件:scr/main/resoucres/db.properties

在启动时,框架初始化需要在web.xml中添加启动配置

在项目中创建对应的配置文件,同时添加web支持

(2)依赖添加

  • spring-core
  • spring-context
  • spring-beans
  • spring-expression
  • spring-insuiession
  • spring-jdbc
  • spring-orm
  • spring-web
  • spring-webmvc
  • mybatis
  • mybatis-spring
  • c3p0
  • mysql-connector-java
pom.xml


    4.0.0

    org.example
    Xiaomi
    1.0-SNAPSHOT

    
        
            mysql
            mysql-connector-java
            8.0.19
        
        
            org.mybatis.generator
            mybatis-generator-core
            1.4.0
        
    
    
    
        org.springframework
        spring-core
        5.2.1.RELEASE
    
    
    
        org.springframework
        spring-beans
        5.2.1.RELEASE
    
    
    
        org.springframework
        spring-context
        5.2.1.RELEASE
    
    
    
        org.springframework
        spring-expression
        5.2.1.RELEASE
    
    
    
        org.springframework
        spring-jdbc
        5.2.1.RELEASE
    
    
    
        org.springframework
        spring-orm
        5.2.1.RELEASE
    
    
    
        org.springframework
        spring-web
        5.2.1.RELEASE
    
    
    
        org.springframework
        spring-webmvc
        5.2.1.RELEASE
    
    
    
        org.mybatis
        mybatis
        3.5.3
    
    
    
        org.mybatis
        mybatis-spring
        2.0.3
    
    
    
        com.mchange
        c3p0
        0.9.5.4
    



(3)细化配置信息

4、单元测试

(1)引入依赖

基于spring的单元测试,需要以下依赖

  • spring-test
  • junit
  • spring-aop
  • aspectj
 
            junit
            junit
            4.12
            test
        
        
            org.springframework
            spring-test
            5.2.1.RELEASE
        
        
            org.springframework
            spring-aop
            5.2.1.RELEASE
        
        
        
        
            org.aspectj
            aspectjweaver
            1.9.5
        

(2)单元测试代码

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class DaoTest {
    @Autowired
    private ConsumerMapper consumerMapper;

    @Test
    public void testConsumerInsert(){
        Consumer consumer = new Consumer("zfz","123");
        //讲consumer添加到数据库 insertSelective在只有部分属性有值时使用
        consumerMapper.insertSelective(consumer);
        System.out.println("insertSelective执行完成");
    }
 }
    

5、业务模型开发&封装响应

从业务模型处理>>复杂业务模型操作

登录、注册>>首页数据加载-->搜索>>购物车>>订单

(1)登录业务

首先创建用户相关业务处理类:com.zfz.xiaomi.service.ConsumerService.java

@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 consumerList = consumerMapper.selectByExample(ce);

        return consumerList != null && consumerList.size() == 1;
    }
}

创建用户相关业务的访问接口/控制器:com.zfz.xiaomi.controller.ConsumerController.java

@Controller
@RequestMapping("/consumer")
public class ConsumerController {

    @Autowired
    private ConsumerService consumerService;

    @PostMapping("/login/auth")
    public String 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业务的单元测试

@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 {
        //发送post请求
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/consumer/login/auth")
                .param("username", "zfz")
                .param("password", "123")).andReturn();

        System.out.println(mvcResult.getResponse().getContentAsString());
    }
}

(2)相应数据封装

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

  • 固定格式的参数,根据需求提供调用接口即可
  • 返回数据-错误码:快捷判断响应结果是否正确的错误标志,HTTP:200 正确;404 未找到资源; 500 服务器内部错误
  • 返回数据-错误描述:针对错误码具体错误信息的描述
  • 返回数据-数据封装:具体包含的一个或者多个数据

在项目中定义工具类型,封装响应数据:com.zfz.xiaomi.utils.ResponsMessage.java

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

    public String getErrorCode() {
        return errorCode;
    }

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

    public String getErrMsg() {
        return errMsg;
    }

    public void setErrMsg(String errMsg) {
        this.errMsg = errMsg;
    }

    public Map getObjectMap() {
        return objectMap;
    }

    public void setObjectMap(Map 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.setErrMsg("处理成功");
        return rm;
    }
    public static ResponseMessage error(){
        ResponseMessage rm = new ResponseMessage();
        rm.setErrorCode("200");
        rm.setErrMsg("处理失败");
        return rm;
    }
    
}

重构登陆业务


    @PostMapping("/login/auth")
    @ResponseBody //@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据。
    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 ? ResponseMessage.success() : ResponseMessage.error();
    }

6、登录

    

7、用户注册

业务层:com.zfz.xiaomi.service.ConsumerService.java

​ 添加注册方法:register()

public String register(Consumer consumer){
        //验证用户名是否存在
        ConsumerExample ce = new ConsumerExample();
        ce.createCriteria().andUsernameEqualTo(consumer.getUsername());

        List consumerList = consumerMapper.selectByExample(ce);
        if(consumerList.size() > 0){
            return "注册失败,用户名已存在";
        }
        return "注册成功";
    }

业务层:com.zfz.xiaomi.service.ConsumerController.java

​ 添加注册方法:register()

  @PostMapping(value = "/register",produces = {"application/json;charset=UTF-8"})
    @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);

    }

网页视图及功能完善

web/register.jsp+'jquery'脚本


    

8、首页数据加载

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

  • 商品类型
  • 每种类型下的商品

开发业务处理层

  • 商品类型: com.zfz.xiaomi.service.GoodsTypeService.java

  • 商品:com.zfz.xiaomi.service.GoodsShippingService.java

    反例:项目设计时充分考虑不同的代码层、组件模块之间的命名规则和规范。避免出现不同模块、不同代码层出现相同/相似名称的类型,降低代码质量和可读性

image-20200224185908599.png

GoodsTypeService.java

@Service
public class GoodsTypeService {

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

    /**
     * 查询二级商品类型
     * @param top 一级商品类型
     * @return 返回对应的二级商品类型
     */
    public List findSecondLevel(GoodsType top){
        GoodsTypeExample gte = new GoodsTypeExample();
        gte.createCriteria().andPidEqualTo(top.getId());
        return goodsTypeMapper.selectByExample(gte);
    }
}

GoodsShippingService.java

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

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

首页数据加载完善

生成的Goods类中不包含图片的地址,在类中添加图片地址的属性

  • com.zfz.xiaomi.entry.Goods.java
private List goodsImages;

    public List getGoodsImages() {
        return goodsImages;
    }

    public void setGoodsImages(List goodsImages) {
        this.goodsImages = goodsImages;
    }
  • mapper/GoodsMapper.xml


  • mapper/GoodsMapper.xml
  
  

    
    
      
      
      
      
    
  

开发首页控制器com.zfz.xiaomi.controller.IndexController.java

  • initIndex(..):加载首页数据的控制器方法,前端网页中通过JQuery Ajax请求获取数据

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

9、商品搜索

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

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

业务层方法开发:com.zfz.xiaomi.service.GoodsShipService.java

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

控制层方法com.zfz.xiaomi.controller.UtilsController.java

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

单元测试

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

网页视图开发

    
    

(2)、商品按类型检索

一级类型查看

首页导>>根据一级类型查看所有商品

业务层:com.zfz.xiaomi.service.GoodsShippingService

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

控制层:com.zfz.xiaomi.controller.UtilsController

/**
     * 根据类型查看商品
     * @param level level 类型级别 1一级类型 2 二级类型
     * @param goodTypeId 类型编号
     * @return 返回响应数据
     */
    @GetMapping("search/{level}/{gtId}")
    public ResponseMessage searchGoodsWithType(@PathVariable Integer level, @PathVariable Integer goodTypeId){

        GoodsType goodsType = goodsTypeService.findById(goodTypeId);
        List goodsList = null;
        if (level == 1){
            goodsList = goodsShippingService.findGoodsWithTopType(goodsType);
        } else if (level == 2){
            goodsList = goodsShippingService.findGoodsWithType(goodsType);
        }
        return goodsList != null && goodsList.size() > 0
                ? ResponseMessage.success().addObject("goodsList", goodsList)
                : ResponseMessage.error();
    }

视图处理web/goodslist2.jsp

  • index.jsp 导航发起
  • 跳转到指定页面goodslist2.jsp
  • 在商品列表页面中,获取查询参数,发送请求获取数据

二级类型查看

楼层商品>>根据二级类型查看更多

10、商品详情处理

业务模型处理方法:com.zfz.xiaomi.service.GoodsShippingService.java
开发业务层处理方法:findGoodsWithId(..),完善对应的GoodsMapper.xml

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

商品详情控制器接口开发:com.zfz.xiaomi.controller.GoodsController.java

@Controller
@RequestMapping("/goods")
public class GoodsController {
    
    @Autowired
    private GoodsShippingService goodsShippingService;
    
    @GetMapping("/detail/{gid}")
    @ResponseBody
    public ResponseMessage findGoodsWithId(@PathVariable Integer gid){
        Goods goods = goodsShippingService.findGoodWithId(gid);
        return ResponseMessage.success().addObject("goods",goods);
    }
}

网页试图处理:‘web/detail.jsp’
跳转index.jsp||goodslist.jsp>>detail.jsp?gid=***发送Ajax请求获取对应的商品信息

11、购物车

商品加入购物车

detail.jsp商品详情页>>加入购物车>>加入购物车流程

业务处理层:com.damu.xiaomi.service.ShopCartService.java

public class ShopCartService {

    @Autowired
    private GoodsCartMapper goodsCartMapper;

    /**
     * 判断某个商品在购物车中是否存在
     * @param consumer 指定用户
     * @param goods 指定商品
     * @return
     */
    private List checkGoods(Consumer consumer, Goods goods){
        //查询指定的商品在当前用户的购物车中是否存在
        GoodsCartExample gce = new GoodsCartExample();
        gce.createCriteria().andConsumerIdEqualTo(consumer.getId()).andGoodsIdEqualTo(goods.getId());
        //查询操作
        List cartList = goodsCartMapper.selectByExample(gce);
        return  cartList;
    }
    
    /**
     * 指定商品加入购物车
     * @param goods 要加入购物车的商品
     * @return 返回加入结果
     */
    public boolean addGoodsToShopCart(Consumer consumer,Goods goods){
        List  cartList = this.checkGoods(consumer, goods);
        if (cartList.size() > 0){
            //更新购买数量
            int count = cartList.get(0).getBuyCount();
            cartList.get(0).setBuyCount(count + 1);
            //更新小计金额
            double totalPrice = cartList.get(0).getSubtotal()/count * cartList.get(0).getBuyCount();
            cartList.get(0).setSubtotal(totalPrice);
        }else {
            //新增商品
            GoodsCart goodsCart = new GoodsCart(goods.getId(),1,new Date(), goods.getPrice(), consumer.getId());
            goodsCartMapper.insertSelective(goodsCart);
        }
        return true;
    }

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

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

重构登陆业务com.zfz.xiaomi.controller.ConsumerCroller.java

  1. 验证密码+账号
  2. 登记用户 -- 会话跟踪【session】
    @PostMapping(value = "/login/auth",produces = {"application/json;charset=UTF-8"})
    @ResponseBody //@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据。
    public ResponseMessage login(@RequestParam String username, @RequestParam String password,
                                 HttpSession 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();
    }

控制层:com.zfz.xiaomi.controller.ShopCartController.java

@Controller
@RequestMapping("/shopcart")
public class ShopCartController {

    @Autowired
    private ShopCartService shopCartService;
    @Autowired
    private GoodsShippingService goodsShippingService;


    /**
     * 商品加入购物车
      * @param goodsId 商品id
     * @param session session中携带consumer信息
     * @return 成功或失败
     */
    @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.findGoodWithId(goodsId);
        shopCartService.addGoodsToShopCart(consumer,goods);
        return ResponseMessage.success();
    }

    /**
     * 从购物车中删除指定商品
     * @param goodsId 商品id
     * @param session session中携带consumer信息
     * @return 成功或失败
     */
    @GetMapping("/remove/{goodsId}")
    public ResponseMessage removeGoodsToCart(@PathVariable Integer goodsId, HttpSession session){
        //获取当前用户
        Consumer consumer = (Consumer) session.getAttribute("loginConsumer");
        if (consumer == null)
            return ResponseMessage.error();
        Goods goods = goodsShippingService.findGoodWithId(goodsId);
        shopCartService.removeGoodsFromShopCart(consumer,goods);
        return ResponseMessage.success();

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

网页视图处理

  • 添加商品到购物车的操作:详情页完成
  • 查看购物车商品:购物车页面
  • 从购物车中删除对应的商品:购物车页面

你可能感兴趣的:(SSM练手之小米商城-笔记)