异步查询工具axios(儿所以时)
vue官方推荐的ajax请求框架
新增品牌页面
如何找到上面这个页面
上面就是请求路径与请求方式
那么请求参数是什么?
brand对象,外加商品分类的id数组cids (这里其实不止就是添加一个分类)
返回值没有就是一个响应,这里201就成功,表明创建了数据
下面我们去写Controller页面
这个Controller就是BrandController
这个Controller里面要增加如下一个方法
这个方法内部的参数是什么?
一个对象,和一个ids的数组
我们先去看一下实际传递的是什么鬼?
这里很明显传递的是一个json对象
这个对象现在要拿到控制器的方法里面去
我用两个参数来接收一个json对象
下面是BrandController里面的保存品牌的方法
下面就去service里面完成saveBrand()这个方法
我先去数据库当中创建一张中间表,因为品牌与分类是有一个多对多的关系
上面就创建了一个中间表
下面先来预先插入一些数据
上面数据是到位了对吧
再回到我们的Service里面
那我们现在去通用mapper里面添加一个方法,并且用注解配置好sql语句
这里必须在注解上写sql和原理,可以去javaee里面mybatis4进行查看
下面我们去完成mapper里面的方法BrandMapper
下面去到我们BrandService里面,有一个saveBrand()方法这个方法我们必须加上spring的事务注解,要么都成功,要么都失败,因为这里涉及到插入了品牌表之后,我们还要去插入品牌表与分类表的中间表
下面我们去测一下我们这个方法,从新启动商品这个微服务
我在测这个模块的时候,给我报了一个错误,就是500
这里就很明显是服务器的代码出了问题,我去测试了一下,直接是连controller层都没有进来,就直接报错了
我怀疑是参数接收的时候没有设置好,从前端传过来的是一个JSON数据,里面包含了一个多选框数据,那么在用List集合进行接收的时候,我们需要加@RequestParam注解
改进如下
修改完了之后,重新启动服务模块
还是会报错,但是这个时候就是给我们响应的一个400的报错
400的报错
这里其实也就是参数中的数据格式出现了问题,我们看一下请求的数据格式
很明显的是这里是一个json的数据格式
来说一下axios的处理请求原则
这里解决方案是你引入npm里面的工具包,QS,这是一个第三方库,安装方式npm install qs --save
我们的项目已经装好了如上
下面我们就要用这个QS对象去修改一下前端页面了,不过这个页面该怎么去找,如何去寻找到这个页面呢
首先找到商品的的vue组件,也就是Brand.vue组件
在我们的目录里面,也就是左边
然后我们再去提交一次查询,发现数据已经不是之前的JSON格式了
但是服务器又报500错误
我们还是去后端进行测试一下
直接看一下给我们报的错误异常
.apache.ibatis.binding.BindingException: Parameter 'cid' not found. Available parameters are [arg1, arg0, param1, param2]
那我把这里做一些修改,用放到dao层的注解Param做一个参数名字的映射
重新启动service模块,然后重新访问
插入成功,这是我刚刚在tb_brand里面插入的一个品牌
现在去关联的表里面看一下,有没有与分类连接起来
下面我们做图片上传功能
文件的上传它并不是只在品牌管理中有需求,以后其他服务可能也需要,因为把它变成一个独立微服务,专门处理各种上传
把它变成一个微服务之后,我们需要导入下面的依赖
下面说一下spring-boot-starter-test的用法
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest
public class MySpringBootApplicationTests {
@Test
public void testSampleMethod() {
// 假设您有一个名为 SampleService 的 Spring Bean,并且它有一个方法返回 "Hello, World!"
SampleService sampleService = new SampleService();
String result = sampleService.getGreeting();
// 使用断言来验证结果是否符合预期
assertEquals("Hello, World!", result);
}
}
解释一下上面的代码
下面我们去编写一下配置文件
server:
port: 8082
spring:
application:
name: upload-service
servlet:
multipart:
max-file-size: 5MB # 限制文件上传大小
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10086/eureka
instance:
lease-renewal-interval-in-seconds: 5 #每隔五秒发送一次心跳,保证这个方法还在
lease-expiration-duration-in-seconds: 10 #10秒不发送心跳就过期,会把服务剔除掉
prefer-ip-address: true
ip-address: 127.0.0.1
instance-id: ${spring.application.name}:${server.port}
下面我们编写spring boot启动类
在我们编写具体的业务代码之前,我们必须弄清楚请求路径,请求蚕丝,请求方式,返回值类型
我们直接在下面这个位置点击上传测试一下下面的路径
首先请求方式:肯定是POST上传
路径:/upload/image
我们可以看到请求参数是一个 文件对象,SpringMVC会把它封装成一个接口:Multiple
返回结果:上传成功之后得到文件的一个url路径
下面我们开始去编写controllerl类
package com.leyou.controller;
import com.leyou.service.UploadService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("upload")
public class UploadController {
//我们需要一个上传的Service对象
@Autowired
private UploadService uploadService;
@PostMapping("image")
public ResponseEntity uploadImage(@RequestParam("file") MultipartFile file) {
String url = uploadService.upload(file);
System.out.println("打印url:" + url);
if(StringUtils.isBlank(url)) {
System.out.println("这里为空串");
//上面的url为空
//为空上传有可能就是参数错误,直接返回400的错误状态码
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
//下面就是成功,返回200状态码与url数据
return ResponseEntity.ok(url);
}
}
下面去service层完成相应的方法
在上传文件中,我们需要对上传内容进行校验:我们这里重点关注过程,不关注代码,代码可以copy
1.检验文件大小
2.检验文件的媒体类型,也就是说互联网传输过程中是什么类型
可以直接去查这个对照表
3.校验文件内容
下面说一下SLF4J(Simple Logging Facade for Java)和Logback来记录日志的使用状况
下面说一下下面这部分内容的含义
// 2)校验图片内容
BufferedImage image = ImageIO.read(
file.getInputStream());
if (image == null) {
logger.info("上传失败,文件内容不符合要求"); return null;
}
下面我们上servcie的完整代码
package com.leyou.service;
import com.leyou.controller.UploadController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;
import java.util.List;
@Service
public class UploadService {
//做一个日志变量,用来记录某个类会出现的错误信息
private static final Logger logger = (Logger) LoggerFactory.getLogger(UploadController.class);
//列出支持的文件类型
//利用Arrays类的asList()方法把支持的类型做成一个集合
private static final List suffixes = Arrays.asList("image/png", "image/jpeg");
//下面去完成主体代码
//MultipartFile file这个是处理文件上传的对象
//他可以获取文件类型信息,还有就是文件的原始名字等等
public String upload(MultipartFile file) {
try {
// 1、图片信息校验
// 1)校验文件类型
String type = file.getContentType();
if (!suffixes.contains(type)) {
logger.info("上传失败,文件类型不匹配:{}", type);
return null;
}
// 2)校验图片内容
BufferedImage image = ImageIO.read(file.getInputStream());
if (image == null) {
logger.info("上传失败,文件内容不符合要求");
return null;
}
// 2、保存图片
// 2.1、生成保存目录
File dir = new File("D:\\pxx\\upload");
if (!dir.exists()) {
dir.mkdirs();
}
// 2.2、保存图片
file.transferTo(new File(dir, file.getOriginalFilename()));
// 2.3、拼接图片地址
String url = "http://image.leyou.com/upload/" + file.getOriginalFilename();
return url;
} catch (Exception e) {
return null;
}
}
}
下面我们用rest client 测试一下这个接口
上面很明显就是接口测试成功
我们看一下上面的路径
http://127.0.0.1:8082/upload/image
这个路径很明显就是绕过了网关的,因为网关会给我们过来的所有连接加上/api前缀
图片上传是文件的传输,如果也经过zuul网关代理,文件就会经过多次网络传输,造成不必要的网络负担,在高并发的情况下,可能会导致网络阻塞,zuul网关不可用,下面我们需要绕过网关处理
我们可以在网关做如下配置过滤某个微服务
但是如果这样配置,首先路径还是不会变,如下
也就是还是回去加上/api 这样一个前缀,但是我们真正想要的链接是
http://127.0.0.1:8082/upload/image
这里多说一点在这个位置,上面api.leyou.com一过来,会路过linux上面的nginx服务器,给我们定向到网关,看一下下面的配置
她会给我们代理到192.168.1.100:10010也就是网关服务器的地址,这里我们是在本机上面配的网关,但很明显我们不想去这,我们想去的还是下面这个地址
http://127.0.0.1:8082/upload/image
下面说一个nginx重写地址并马上进行转发的指令rewirte指令
下面我们贴一个路径规则,然后来进行讲解一下
那么这里我们先去重写一下这个匹配规则
先贴一个原来的路径转发
上面还是保留一下原来的,我们配置一下现在的访问目录就行了,比如这个是/api/upload这样一个访问目录,也就是主机过来之后,遇到后面跟这样一个访问目录,就会跳到这个location位置给我们进行转发,但是,需要注意的一个问题是,这个配置必须写到location /这样一个位置前面,因为location \这个是一个相当于通配,并且它的配置级别比较大,/api/upload这样路径一过来,其实不止是这个路径,是任意路径一过来,一旦第一个匹配直接找到location /,那么就会进去,执行相应的转发代理
话不多说,我们来配置一下nginx 服务器
难道就是说上面这样配置一下就好了吗
如果我们只是上面这样匹配了一下,还是会出问题,因为下面的路径一过来
上面是原本的请求路径
然后经过上面代理,注意我们这里代理只是改变ip,不会把中间的请求路径也替换掉,所以路径会变成下面的样子
http://192.168.1.1000:8082/api/upload/image
但是就是即使是这个路径,前面还是会带有前缀,这个前缀还是会带有api,也就是当网关检测到有api这个路径之后,这个路径还是会被网关拦截,那么这里我们需要去做一个路径的复写,nginx给我们提供了一个路径复写的指令
下面详细讲解一下这个路径复写的规则
经过上面的处理,路径就会变成下面的方式
http://192.168.1.1000:8082/upload/image
这个就是我们想要的路径,直达文件微服务
注意修改之后重新启动nginx
看一下conf的完整配置
403是表示服务器拒绝这个请求
看一下控制台报错,这里应该是报了一个跨域错误
为什么跨域出错,因为我们这个请求没有走网关,网关会处理跨域,但是ly-upl;oad这个微服务不会给我们处理跨域,所以,我们把之前那做的跨域放到这里来
重新启动一下我们上传的这个微服务
下面我们把跨域代码全部贴一下
package com.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;
/**
* @Author: TianCi.Xiong
* @Description: 跨域配置
* @Date: Created in 2019-11-02 17:22
*/
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//1) 允许的域,不要写*,否则cookie就无法使用了
config.addAllowedOrigin("http://manage.leyou.com");
config.addAllowedOrigin("http://www.leyou.com");
//2) 是否发送Cookie信息
config.setAllowCredentials(true);
//3) 允许的请求方式
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("POST");
config.addAllowedHeader("*");
//2.添加映射路径,我们拦截一切请求
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}
然后我们重新调用上传
上面很明显是200访问吗成功,服务器会给我们 返回一个图片地址
至于这个里面还是会给我们报错
我们后面再来处理这个.
好了,第三篇也就先说到这,祝大家早安午安晚安。