商城的核心自然是商品,而商品多了以后,肯定要进行分类,并且不同的商品会有不同的品牌信息,我们需要依次去完成:商品分类、品牌、商品的开发。
1.导入数据库表

打开Navicat软件,选择对应的数据库,运行sql文件。


执行结果:

2.
根据这个路由路径到路由文件(src/route/index.js),可以定位到分类管理页面:

由路由文件知,页面是src/pages/item/Category.vue

商品分类使用了树状结构,而这种结构的组件vuetify并没有为我们提供,这里自定义了一个树状组件。不要求实现或者查询组件的实现,只要求可以参照文档使用该组件即可:

(1)url异步请求

http://manage.leyou.com/item/category/list
但实际却是:
http://api.leyou.com/api/item/category/list?pid=0
这就会出现跨域问题(第3大点分析)
这是因为,我们有一个全局的配置文件,对所有的请求路径进行了约定:

package lucky.leyou.item.domain;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Table(name="tb_category")
public class Category {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String name;
private Long parentId;
// 注意isParent生成的getter和setter方法需要手动加上Is
//实际开发中尽量避免数据库字段名以is开头
private Boolean isParent;
private Integer sort;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
public Boolean getIsParent() {
return isParent;
}
public void setIsParent(Boolean parent) {
isParent = parent;
}
public Integer getSort() {
return sort;
}
public void setSort(Integer sort) {
this.sort = sort;
}
}
GeneratedValue
<dependencies>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
(3)mapper

我们使用通用mapper来简化开发:
package lucky.leyou.item.mapper;
import lucky.leyou.item.domain.Category;
import tk.mybatis.mapper.common.Mapper;
public interface CategoryMapper extends Mapper<Category> {
}
package lucky.leyou;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import tk.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("lucky.leyou.item.mapper") // mapper接口的包扫描
public class LeyouItemServiceApplication {
public static void main(String[] args) {
SpringApplication.run(LeyouItemServiceApplication.class, args);
}
}
(4)service
一般service层我们会定义接口和实现类。
接口:
package lucky.leyou.item.service;
import lucky.leyou.item.domain.Category;
import java.util.List;
public interface ICategoryService {
/**
* 根据parentId查询子类目
* @param pid
* @return
*/
public List<Category> queryCategoriesByPid(Long pid);
}
实现类:
package lucky.leyou.item.service.impl;
import lucky.leyou.item.domain.Category;
import lucky.leyou.item.mapper.CategoryMapper;
import lucky.leyou.item.service.ICategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class CategoryServiceImpl implements ICategoryService {
@Autowired
private CategoryMapper categoryMapper;
/**
* 根据parentId查询子类目
* @param pid
* @return
*/
@Override
public List<Category> queryCategoriesByPid(Long pid) {
Category record = new Category();
record.setParentId(pid);
return this.categoryMapper.select(record);
}
}
(5)Controller
-
请求方式:决定我们用GetMapping还是PostMapping
-
请求路径:决定映射路径
-
请求参数:决定方法的参数
-
返回值结果:决定方法的返回值
- 请求方式:Get,查询肯定是get请求
- 请求路径:/api/item/category/list。其中/api是网关前缀,/item是网关的路由映射,真实的路径应该是/category/list
- 请求参数:pid=0,根据tree组件的说明,应该是父节点的id,第一次查询为0,那就是查询一级类目
模块结构:

添加Controller:
package lucky.leyou.item.controller;
import lucky.leyou.item.domain.Category;
import lucky.leyou.item.service.ICategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Controller
@RequestMapping(path = "/category")
public class CategoryController {
@Autowired
private ICategoryService iCategoryService;
/**
* 根据parentId查询子类目
* @param pid @RequestParam(value = "pid",defaultValue = "0") long pid 作用:接收url中携带的请求参数,设置默认值为0
* @return
*/
@RequestMapping("/list")
public ResponseEntity<List<Category>> queryCategoriesByPid(@RequestParam(value = "pid",defaultValue = "0") Long pid){
if(pid==null||pid<0){
//响应类型400:如果pid为null或pid<0,返回请求参数不合法
return ResponseEntity.badRequest().build();
}
List<Category> categories = this.iCategoryService.queryCategoriesByPid(pid);
//利用CollectionUtils.isEmpty(categories)判断集合是否为空
if(CollectionUtils.isEmpty(categories)){
//响应类型404:资源服务器未找到
return ResponseEntity.notFound().build();
}
//响应类型200:查询成功
return ResponseEntity.ok(categories);
}
}
(6)启动并测试
<3>刷新后台管理页面查看:

这其实是浏览器的同源策略造成的跨域问题。
3.
以下情况都属于跨域:
如果域名和端口都相同,但是请求路径不同,不属于跨域,如:
www.jd.com/item
www.jd.com/goods
http和https也属于跨域
而我们刚才是从manage.leyou.com去访问api.leyou.com
因为跨域问题是浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是与当前页域名相同的路径,这能有效的阻止跨站攻击。
因此:跨域问题 是针对ajax的一种限制。
优势:
-
在服务端进行控制是否允许跨域,可自定义规则
-
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
-
浏览器端:
-
服务端:
<2>CORS解决跨域实现
SpringMVC已经帮我们写好了CORS的跨域过滤器:CorsFilter ,内部已经实现了刚才所讲的判定逻辑,我们直接用就好了。
代码:
package lucky.leyou.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* 利用cors解决跨域问题
*/
@Configuration
public class LeyouCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//1) 允许的域,不要写*,否则cookie就无法使用了
config.addAllowedOrigin("http://manage.leyou.com");
//2) 是否发送Cookie信息
config.setAllowCredentials(true);
//3) 允许的请求方式
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
// 4)允许的头信息
config.addAllowedHeader("*");
//2.添加映射路径,我们拦截一切请求
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}
重启网关模块leyou-gateway2,然后在浏览器中测试,访问正常:

若出现leyou-gateway2模块中报如下错误com.netflix.zuul.exception.ZuulException: Forwarding error
解决方案:将如下的3个服务全部重新启动。






