乐优商城(三十三)——购物车

目录

四、已登录购物车

4.1 添加登录校验

4.1.1 引入JWT相关依赖

4.1.2 配置公钥

4.1.3 加载公钥

4.1.4 编写拦截器

4.1.5 配置拦截器

4.1.6 编写过滤器

4.1.7 配置过滤器

4.2 后台购物车设计

4.3 添加商品到购物车

4.3.1 页面发起请求

4.3.2 编写Controller

4.3.3 CartService

4.3.4 GoodClient

4.3.5 结果

4.4 查询购物车

4.4.1 页面发起请求

4.4.2 后台实现

4.4.3 测试

4.5 修改商品数量

4.5.1 页面发起请求

4.5.2 后台实现

4.6 删除购物车商品

4.6.1 页面发起请求

4.6.2 后台实现

五、登陆后购物车合并

5.1 前端

5.2 后端

5.3 测试

5.3.1 未登录

5.3.2 登录

5.4 问题


 

四、已登录购物车

4.1 添加登录校验

购物车系统只负责登录状态的购物车处理,因此需要添加登录校验,通过JWT鉴权即可实现。

4.1.1 引入JWT相关依赖

        <dependency>
            <groupId>com.leyou.authentication</groupId>
            <artifactId>leyou-authentication-common</artifactId>
        </dependency>

4.1.2 配置公钥

leyou:
  jwt:
    cookieName: LY_TOKEN
    pubKeyPath: G:\\tmp\\rsa\\rsa.pub # 公钥地址

4.1.3 加载公钥

代码:

package com.leyou.cart.config;

import com.leyou.auth.utils.RsaUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;

import javax.annotation.PostConstruct;
import java.io.File;
import java.security.PublicKey;

/**
 * @Author: 98050
 * @Time: 2018-10-25 16:12
 * @Feature: jwt属性
 */
@ConfigurationProperties(prefix = "leyou.jwt")
public class JwtProperties {
    /**
     * 公钥
     */
    private PublicKey publicKey;

    /**
     * 公钥地址
     */
    private String pubKeyPath;

    /**
     * cookie名字
     */
    private String cookieName;

    private static final Logger logger = LoggerFactory.getLogger(JwtProperties.class);

    public PublicKey getPublicKey() {
        return publicKey;
    }

    public void setPublicKey(PublicKey publicKey) {
        this.publicKey = publicKey;
    }

    public String getPubKeyPath() {
        return pubKeyPath;
    }

    public void setPubKeyPath(String pubKeyPath) {
        this.pubKeyPath = pubKeyPath;
    }

    public String getCookieName() {
        return cookieName;
    }

    public void setCookieName(String cookieName) {
        this.cookieName = cookieName;
    }

    public static Logger getLogger() {
        return logger;
    }

    /**
     * @PostConstruct :在构造方法执行之后执行该方法
     */
    @PostConstruct
    public void init(){
        try {
            File pubKey = new File(pubKeyPath);
            // 获取公钥
            this.publicKey = RsaUtils.getPublicKey(pubKeyPath);
        } catch (Exception e) {
            logger.error("获取公钥失败!", e);
            throw new RuntimeException();
        }
    }
}

4.1.4 编写拦截器

因为很多接口都需要进行登录,直接编写SpringMVC拦截器,进行统一登录校验。同时,还要把解析得到的用户信息保存起来,以便后续的接口可以使用。

package com.leyou.cart.interceptor;

import com.leyou.auth.entity.UserInfo;
import com.leyou.auth.utils.JwtUtils;
import com.leyou.cart.config.JwtProperties;
import com.leyou.utils.CookieUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Author: 98050
 * @Time: 2018-10-25 18:17
 * @Feature: 登录拦截器
 */
public class LoginInterceptor extends HandlerInterceptorAdapter {

    private JwtProperties jwtProperties;

    /**
     * 定义一个线程域,存放登录用户
     */
    private static final ThreadLocal<UserInfo> t1 = new ThreadLocal<>();

    public LoginInterceptor(JwtProperties jwtProperties) {
        this.jwtProperties = jwtProperties;
    }

    /**
     *      * 在业务处理器处理请求之前被调用
     *      * 如果返回false
     *      *      则从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链
     *      * 如果返回true
     *      *      执行下一个拦截器,直到所有拦截器都执行完毕
     *      *      再执行被拦截的Controller
     *      *      然后进入拦截器链
     *      *      从最后一个拦截器往回执行所有的postHandle()
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.查询token
        String token = CookieUtils.getCookieValue(request,jwtProperties.getCookieName());
        if (StringUtils.isBlank(token)){
            //2.未登录,返回401
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        }
        //3.有token,查询用户信息
        try{
            //4.解析成功,说明已经登录
            UserInfo userInfo = JwtUtils.getInfoFromToken(token,jwtProperties.getPublicKey());
            //5.放入线程域
            t1.set(userInfo);
            return true;
        }catch (Exception e){
            //6.抛出异常,证明未登录,返回401
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        }
    }

    /**
     * 在业务处理器处理请求执行完成后,生成视图之前执行的动作
     * 可在modelAndView中加入数据,比如当前时间
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等
     * 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion()
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
       t1.remove();
    }
    
    public static UserInfo getLoginUser(){
        return t1.get();
    }
}

注意:

  • 这里使用了ThreadLocal来存储查询到的用户信息,线程内共享,因此请求到达Controller后可以共享User

  • 并且对外提供了静态的方法:getLoginUser()来获取User信息

4.1.5 配置拦截器

package com.leyou.cart.config;

import com.leyou.cart.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Author: 98050
 * @Time: 2018-10-25 19:48
 * @Feature: 配置过滤器
 */
@Configuration
@EnableConfigurationProperties(JwtProperties.class)
public class MvcConfig implements WebMvcConfigurer {

    @Autowired
    private JwtProperties jwtProperties;

    @Bean
    public LoginInterceptor loginInterceptor(){
        return new LoginInterceptor(jwtProperties);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor()).addPathPatterns("/**");
    }
}

4.1.6 编写过滤器

以后使用

package com.leyou.cart.filter;


import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * @Author: 98050
 * @Time: 2018-10-25 20:00
 * @Feature:
 */
@WebFilter(filterName = "CartFilter",urlPatterns = {"/**"})
public class CartFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("具体过滤规则");
    }

    @Override
    public void destroy() {
        System.out.println("销毁");
    }
}

4.1.7 配置过滤器

两种方式:

注解

配置类

4.2 后台购物车设计

当用户登录时,需要把购物车数据保存到后台,可以选择保存在数据库。但是购物车是一个读写频率很高的数据。因此这里选择读写效率比较高的Redis作为购物车存储。

Redis有5种不同数据结构,这里选择哪一种比较合适呢?

  • 首先不同用户应该有独立的购物车,因此购物车应该以用户的作为key来存储,Value是用户的所有购物车信息。这样看来基本的k-v结构就可以了。

  • 但是,对购物车中的商品进行增、删、改操作,基本都需要根据商品id进行判断,为了方便后期处理,购物车中的商品也应该是k-v结构,key是商品id,value才是这个商品的购物车信息。

综上所述,购物车结构是一个双层Map:Map<String,Map<String,String>>

  • 第一层Map,Key是用户id

  • 第二层Map,Key是购物车中商品id,值是购物车数据

实体类:

package com.leyou.cart.pojo;

/**
 * @Author: 98050
 * @Time: 2018-10-25 20:27
 * @Feature: 购物车实体类
 */
public class Cart {
    /**
     * 用户Id
     */
    private Long userId;

    /**
     * 商品id
     */
    private Long skuId;

    /**
     * 标题
     */
    private String title;

    /**
     * 图片
     */
    private String image;

    /**
     * 加入购物车时的价格
     */
    private Long price;
    
    /**
     * 购买数量
     */
    private Integer num;

    /**
     * 商品规格参数
     */
    private String ownSpec;

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public Long getSkuId() {
        return skuId;
    }

    public void setSkuId(Long skuId) {
        this.skuId = skuId;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public Long getPrice() {
        return price;
    }

    public void setPrice(Long price) {
        this.price = price;
    }

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer num) {
        this.num = num;
    }

    public String getOwnSpec() {
        return ownSpec;
    }

    public void setOwnSpec(String ownSpec) {
        this.ownSpec = ownSpec;
    }
}

4.3 添加商品到购物车

4.3.1 页面发起请求

已登录情况下,向后台添加购物车:

这里发起的是json请求,那么后台接收也要以json接收。

4.3.2 编写Controller

先分析一下:

  • 请求方式:新增,肯定是Post

  • 请求路径:/cart ,这个其实是Zuul路由的路径,可以不管

  • 请求参数:Json对象,包含skuId和num属性

  • 返回结果:无

package com.leyou.cart.controller;

import com.leyou.cart.pojo.Cart;
import com.leyou.cart.service.CartService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

/**
 * @Author: 98050
 * @Time: 2018-10-25 20:41
 * @Feature:
 */
@Controller
public class CartController {

    @Autowired
    private CartService cartService;

    @PostMapping
    public ResponseEntity<Void> addCart(@RequestBody Cart cart){
        this.cartService.addCart(cart);
        return ResponseEntity.ok().build();
    }
}

在网关中添加路由配置:

4.3.3 CartService

这里不直接访问数据库,而是直接操作Redis。基本思路:

  • 先查询之前的购物车数据

  • 判断要添加的商品是否存在

    • 存在:则直接修改数量后写回Redis

    • 不存在:新建一条数据,然后写入Redis

代码:

接口

package com.leyou.cart.service;

import com.leyou.cart.pojo.Cart;

/**
 * @Author: 98050
 * @Time: 2018-10-25 20:47
 * @Feature:
 */
public interface CartService {
    /**
     * 添加购物车
     * @param cart
     */
    void addCart(Cart cart);
}

实现

package com.leyou.cart.service.impl;

import com.leyou.auth.entity.UserInfo;
import com.leyou.cart.client.GoodsClient;
import com.leyou.cart.interceptor.LoginInterceptor;
import com.leyou.cart.pojo.Cart;
import com.leyou.cart.service.CartService;
import com.leyou.item.pojo.Sku;
import com.leyou.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

/**
 * @Author: 98050
 * @Time: 2018-10-25 20:48
 * @Feature:
 */
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private GoodsClient goodsClient;

    private static String KEY_PREFIX = "leyou:cart:uid:";

    private final Logger logger = LoggerFactory.getLogger(CartServiceImpl.class);

    /**
     * 添加购物车
     * @param cart
     */
    @Override
    public void addCart(Cart cart) {
        //1.获取用户
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        //2.Redis的key
        String key = KEY_PREFIX + userInfo.getId();
        //3.获取hash操作对象
        BoundHashOperations<String,Object,Object> hashOperations = this.stringRedisTemplate.boundHashOps(key);
        //4.查询是否存在
        Long skuId = cart.getSkuId();
        Integer num = cart.getNum();
        Boolean result = hashOperations.hasKey(skuId.toString());
        if (result){
            //5.存在,获取购物车数据
            String json = hashOperations.get(skuId.toString()).toString();
            cart = JsonUtils.parse(json,Cart.class);
            //6.修改购物车数量
            cart.setNum(cart.getNum() + num);
        }else{
            //7.不存在,新增购物车数据
            cart.setUserId(userInfo.getId());
            //8.其他商品信息,需要查询商品微服务
            Sku sku = this.goodsClient.querySkuById(skuId);
            cart.setImage(StringUtils.isBlank(sku.getImages()) ? "" : StringUtils.split(sku.getImages(),",")[0]);
            cart.setPrice(sku.getPrice());
            cart.setTitle(sku.getTitle());
            cart.setOwnSpec(sku.getOwnSpec());
        }
        //9.将购物车数据写入redis
        hashOperations.put(cart.getSkuId().toString(),JsonUtils.serialize(cart));
    }
}

需要引入leyou-item-interface依赖:

        <dependency>
            <groupId>com.leyou.item.interface</groupId>
            <artifactId>leyou-item-interface</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>

4.3.4 GoodClient

package com.leyou.cart.client;

import com.leyou.item.api.GoodsApi;
import org.springframework.cloud.openfeign.FeignClient;

/**
 * @Author: 98050
 * @Time: 2018-10-25 21:03
 * @Feature:商品FeignClient
 */
@FeignClient(value = "item-service")
public interface GoodsClient extends GoodsApi {
}

在leyou-item-service中的GoodsController添加方法:

    @GetMapping("/sku/{id}")
    public ResponseEntity<Sku> querySkuById(@PathVariable("id") Long id){
        Sku sku = this.goodsService.querySkuById(id);
        if (sku == null){
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }
        return ResponseEntity.ok(sku);
    }

在leyou-item-service中的GoodsService添加方法:

    /**
     * 查询sku根据id
     * @param id
     * @return
     */
    Sku querySkuById(Long id);

实现:

    /**
     * 根据skuId查询sku
     * @param id
     * @return
     */
    @Override
    public Sku querySkuById(Long id) {
        return this.skuMapper.selectByPrimaryKey(id);
    }

在leyou-item-interface中GoodsApi中新增接口:

    /**
     * 根据sku的id查询sku
     * @param id
     * @return
     */
    @GetMapping("/sku/{id}")
    Sku querySkuById(@PathVariable("id") Long id);

4.3.5 结果

4.4 查询购物车

4.4.1 页面发起请求

购物车页面:cart.html

 

4.4.2 后台实现

Controller

    /**
     * 查询购物车
     * @return
     */
    @GetMapping
    public ResponseEntity<List<Cart>> queryCartList(){
        List<Cart> carts = this.cartService.queryCartList();
        if(carts == null){
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }
        return ResponseEntity.ok(carts);
    }

Service

接口:

实现:

    /**
     * 查询购物车
     * @return
     */
    @Override
    public List<Cart> queryCartList() {
        //1.获取登录的用户信息
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        //2.判断是否存在购物车
        String key = KEY_PREFIX + userInfo.getId();
        if (!this.stringRedisTemplate.hasKey(key)) {
            //3.不存在直接返回
            return null;
        }
        BoundHashOperations<String,Object,Object> hashOperations = this.stringRedisTemplate.boundHashOps(key);
        List<Object> carts = hashOperations.values();
        //4.判断是否有数据
        if (CollectionUtils.isEmpty(carts)){
            return null;
        }
        //5.查询购物车数据
        return carts.stream().map( o -> JsonUtils.parse(o.toString(),Cart.class)).collect(Collectors.toList());
    }

4.4.3 测试

购物车:

redis中数据:

4.5 修改商品数量

4.5.1 页面发起请求

4.5.2 后台实现

Controller

    /**
     * 修改购物车中商品数量
     * @return
     */
    @PutMapping
    public ResponseEntity<Void> updateNum(@RequestParam("skuId") Long skuId,@RequestParam("num") Integer num){
        this.cartService.updateNum(skuId,num);
        return ResponseEntity.ok().build();
    }

Service

接口:

实现:

    /**
     * 更新购物车中商品数量
     * @param skuId
     * @param num
     */
    @Override
    public void updateNum(Long skuId, Integer num) {
        //1.获取登录用户
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        String key = KEY_PREFIX + userInfo.getId();
        BoundHashOperations<String,Object,Object> hashOperations = this.stringRedisTemplate.boundHashOps(key);
        //2.获取购物车
        String json = hashOperations.get(skuId.toString()).toString();
        Cart cart = JsonUtils.parse(json,Cart.class);
        cart.setNum(num);
        //3.写入购物车
        hashOperations.put(skuId.toString(),JsonUtils.serialize(cart));
    }

4.6 删除购物车商品

4.6.1 页面发起请求

4.6.2 后台实现

Controller

     /**
     * 删除购物车中的商品
     * @param skuId
     * @return
     */
    @DeleteMapping("{skuId}")
    public ResponseEntity<Void> deleteCart(@PathVariable("skuId") String skuId){
        this.cartService.deleteCart(skuId);
        return ResponseEntity.ok().build();
    }

Service

接口:

 

实现:

    /**
     * 删除购物车中的商品
     * @param skuId
     */
    @Override
    public void deleteCart(String skuId) {
        //1.获取登录用户
        UserInfo userInfo = LoginInterceptor.getLoginUser();
        String key = KEY_PREFIX + userInfo.getId();
        BoundHashOperations<String,Object,Object> hashOperations = this.stringRedisTemplate.boundHashOps(key);
        //2.删除商品
        hashOperations.delete(skuId);
    }

五、登陆后购物车合并

当跳转到购物车页面,查询购物车列表前,需要判断用户登录状态,

  • 如果登录:

    • 首先检查用户的LocalStorage中是否有购物车信息,

    • 如果有,则提交到后台保存,

    • 清空LocalStorage

  • 如果未登录,直接查询即可

5.1 前端

修改cart.html中的loadCarts函数,如果登录成功,则读取本地LocalStorage数据,不为空,则请求后台合并数据

 

5.2 后端

同添加购物车

5.3 测试

5.3.1 未登录

页面:

LocalStorage:

redis中没有数据:

5.3.2 登录

页面:

redis中:

本地存储:

5.4 问题

数据同步失败,在未登录状态下将商品添加到购物车,然后点击登录,会发现查询购物车列表失败,404。

解决方法:数据合并不要放在购物车数据加载中,应该放在登录成功的时候:

问题解决~

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
自己做的乐优商城的XMIND文件,学习分享下。乐优商城 搭建父工程 pom.xml 添加依赖 springCloud mybatis启动器 通用Mapper启动器 mysql驱动 分页助手启动器 FastDFS客户端 其他配置 构建设置 环境设置 EurekaServer注册中心 添加的依赖 启动类 application.yml 创建Zuul网关 依赖 启动类 application.yml 创建商品微服务 ly-item-interface:主要是对外暴露的API接口及相关实体类 ly-item-service:所有业务逻辑及内部使用接口 创建父工程ly-item ly-item-interface ly-item-service 依赖 启动器 application.yml 添加商品微服务的路由规则 通用工具模块Common utils CookieUtils IdWorker JsonUtils NumberUtils 依赖 通用异常处理 测试结构 pojo service @Service web @RestController @RequestMapping @Autowired @PostMapping 引入Common依赖 Common advice 拦截异常、 CommonExceptionHandler ResponseEntity @ControllerAdvice @ExceptionHandler enums 异常的枚举 、ExceptionEnum exception 自定义异常、LyException 接口RuntimeException @Getter @NoArgsConstructor @AllArgsConstructor vo 异常结果处理对象、ExceptionResult @Data 构造方法ExceptionResult ly-item-service CategoryQuery 分类查询 实体类 @Table(name="tb_category") 声明此对象映射到数据库的数据表,通过它可以为实体指定表(talbe) @Data 注解在类上, 为类提供读写属性, 此外还提供了 equals()、hashCode()、toString() 方法 @Id & @GeneratedValue(strategy= GenerationType.IDENTITY) 自动增长,适用于支持自增字段的数据库 mapper Mapper IdListMapper 根据id操作数据库 @RequestMapping("category") Controller @RestController @Controller 处理HTTP请求 @ResponseBody 返回 json 数据 @GetMapping("list") ResponseEntity @ResponseBody可以直接返回Json结果 不仅可以返回json结果,还可以定义返回的HttpHeaders和HttpStatus service @Service 自动注册到Spring容器,不需要再在applicationContext.xml文件定义bean了 @Autowired 它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 select select * from category c where c.pid = #{pid} CollectionUtils.isnotblank 判断集合是否为空 测试 可以利用url直接查询数据库,能否访问得到数据 报错 启动类 没有扫描到 @MapperScan("com.leyou.item.mapper") ,目录结构关系 访问网页报错 CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. 跨域问题 浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是于当前页同域名的路径,这能有效的阻止跨站攻击。因此:跨域问题 是针对ajax的一种限制。 解决跨域问题的方案 CORS 规范化的跨域请求解决方案,安全可靠 什么是cors 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。 原理 简单请求 当浏览器发现发现的ajax请求是简单请求时,会在请求头中携带一个字段:Origin 如果服务器允许跨域,需要在返回的响应头中携带下面信息 Access-Control-Allow-Origin:可接受的域,是一个具体域名或者*,代表任意 Access-Control-Allow-Credentials:是否允许携带cookie,默认情况下,cors不会携带cookie,除非这个值是true 实现非常简单 gateway网关中编写一个配置类 GlobalCorsConfig 添加CORS配置信息 允许的域,不要写*,否则cookie就无法使用了 是否发送Cookie信息 允许的请求方式 允许的头信息 有效时长 添加映射路径,我们拦截一切请求 返回新的CorsFilter 提交方式 GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源 BUG 分类不能打开,当添加后却能打开。 修改一天的BUG 最后发现是实体类里属性大小写的问题引起。 注意 Bule_bird 就必须写成 BlueBird Brand 查询 实体类 PageResult 响应结果 分页结果一般至少需要两个数据 总条数 total 当前页数据 items 有些还需要总页数 总页数 totalPage Controller @RequestParam(value = "page",defaultValue = "1") Integer page GET和POST请求传的参数会自动转换赋值到@RequestParam 所注解的变量上 defaultValue 默认值 required 默认值为true , 当为false时 这个注解可以不传这个参数 null || .size()==0 ResponseEntity(HttpStatus.NOT_FOUND) 返回404没找到 ResponseEntity.ok 返回ok状态 service 开始分页 通用分页拦截器 PageHelper.startPage(page,row); 过滤 Example查询 Example example = new Example(Brand.class); mybatis的逆向工程中会生成实例及实例对应的example,example用于添加条件,相当where后面的部分 xxxExample example = new xxxExample(); Criteria criteria = new Example().createCriteria(); StringUtils.isNotBlank isNotBlank(str) 等价于 str != null && str.length > 0 && str.trim().length > 0 str.trim() 去掉字符串头尾的空格 测试 报错500 com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'idASC' in 'order clause' 错误:(desc ? "DESC" : "ASC"); 正确:(desc ? " DESC" : " ASC"); 字符串空格问题 新增 Controller (Brand brand,@RequestParam("cids") List cids) ResponseEntity 无返回值 new ResponseEntity(HttpStatus.CREATED); 201成功 service @Transactional 自动纳入 Spring 的事务管理 使用默认配置,抛出异常之后,事务会自动回滚,数据不会插入到数据库。 setId(null) insert(brand) 新增中间表 mapper @Insert (#{cid},#{bid}) @Param 表示给参数命名,名称就是括号中的内容 name 命名为aa,然后sql语句....where s_name= #{aa} 中就可以根据aa得到参数值 修改 回显 Controller @PathVariable("bid") 通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的入参中。 select * from tb_category where id in (select category_id from tb_category_brand where brand_id = #{bid}) 测试 报错500 空指针异常 调用Service时候 忘记@Autowired 保存 VO视图对象 @NoArgsConstructor 生成一个无参数的构造方法 @AllArgsConstructor 会生成一个包含所有变量 Controller @PutMapping 添加信息,倾向于用@PostMapping,如果是更新信息,倾向于用@PutMapping。两者差别不是很明显 return ResponseEntity.ok().build(); 无返回值 service 根据id修改 先删除后新增 删除(前端有问题,待完善) spec Group 品牌分类id查询 实体类 @Transient 指定该属性或字段不是永久的。 它用于注释实体类,映射超类或可嵌入类的属性或字段。 @Column(name = "'numeric'") 用来标识实体类中属性与数据表中字段的对应关系 name 定义了被标注字段在数据库表中所对应字段的名称; mapper service Controller 测试 报错500 实体类@table路径写错 新增 Controller @RequestBody 常用其来处理application/json类型 子主题 2 将请求体中的JSON字符串绑定到相应的bean上 修改 Controller @PutMapping service updateByPrimaryKey 删除 Controller @DeleteMapping @PathVariable Param 规格组id查询规格 url:params?gid=14 @GetMapping("params") Controller @RequestParam 新增 @PostMapping("param") @RequestBody ResponseEntity.status(HttpStatus.CREATED).build(); 修改 @RequestBody 删除 @PathVariable 分支主题 3 遇到的问题 pom.xml 文件未下载完整,删掉后重新下载 能存在重复文件,IDEA不能确定文件路径,需要搜索删掉多余的 Param 删除 小问题:数据库删除后页面没有立即显示 Brand 删除(前端有问题,待完善)
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值