javaee之黑马乐优商城3

news2024/9/21 8:04:37

异步查询工具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<String> 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<String> 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

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访问吗成功,服务器会给我们 返回一个图片地址

 

至于这个里面还是会给我们报错

 

 我们后面再来处理这个.

好了,第三篇也就先说到这,祝大家早安午安晚安。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1013862.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯mini项目-【指标监控服务重构】2023-07-31

今日已办 trace_id传播 关于如何使用 trace_id 创建 span 的思路 【暂未实现 & 测试】 调研 SpanProcessor 阅读源码的test 明日待办 根据 trace_id 创建 span&#xff0c;应该需要 parent span_id 才能有 trace 的树状 span 的关系

腾讯mini项目-【指标监控服务重构】2023-08-06

今日已办 feature/client_traces_profile 修改 consumer 4个阶段的 spankind将 profile 的 span 作为 root span&#xff0c;保持与 venus 的 follows from 的 link feature/profile-otelclient-metric 将 metric 部分使用新分支 push go.opentelemetry.io/otel/propagatio…

定时器类的编写与解析 —— TinyWebServer

定时器类的编写与解析 —— TinyWebServer 一、前言 定时器非常好写。就是链表加定时函数。搞懂他的作用就成。 定时器的作用是什么&#xff1f;什么是回调函数&#xff1f;用到的函数是什么&#xff1f; 二、问题回答 Ⅰ、定时器的作用是什么&#xff1f; 处理非活跃的连…

坦克大战设计与实现

摘 要 J2SE是近年来随着各种不同技术的发展&#xff0c;尤其是编程语言飞速发展而诞生的一项新的开发语言。随着信息技术的飞速发展&#xff0c;计算机的使用也日渐普及&#xff0c;本文从实际应用出发&#xff0c;向大家介绍坦克大战游戏的设计与实现。Eclipse平台模拟器开发调…

华为数通方向HCIP-DataCom H12-831题库(单选题:21-40)

第21题 R3与R1的IS-IS邻居没有建立,根据本图的信息,可能的原因是? A、R3与R1的IIH认证失败 B、R3与R1的System ID重复 C、R3与R1的IS-Level不匹配 D、R3与R1的互连接口circuit-type不匹配 答案: A 解析: 从图中的Bad Authentiaction 信息可以看出R3与R1的IIH认证失败失败…

一生一芯16——安装pandoc使jupyter notebook转pdf

目的 希望导出jupyter notebook文档翻译 从这里导出pdf&#xff0c;但显示我没有安装pandoc&#xff0c;故安装pandoc 安装Pandoc 下载对应安装包 https://github.com/jgm/pandoc/releases 下载完成后&#xff0c;在目录中运行程序如下&#xff1a; 你需要解压下载的文件。…

windows10使用wheel安装tensorflow2.13.0/2.10.0(GPU版本) (保姆级教程)

安装过程 安装虚拟环境安装virtualenv安装满足要求的python版本使用virtualenv创建指定python版本的虚拟环境 安装tensorflow安装tensorflow-docs直接下载使用wheel下载 在VSCode编辑器中使用虚拟环境下的python解释器&#xff0c;并使用tensorflow常见错误 注意&#xff1a; t…

Python stomp 发送消息无法显示文本

我们向消息服务器通过 stomp 发送的是文本消息。 当消息服务器发送成功后&#xff0c;消息服务器上的文本没有显示&#xff0c;显示的是 2 进制的数据。 如上图&#xff0c;消息没有作为文本来显示。 问题和解决 消息服务器是如何判断发送的小时是文本还是二进制的。 根据官…

API接口文档管理系统平台搭建(更新,附系统源码及教程)

简介 这是一款简洁大方的API接口文档管理系统&#xff0c;附系统源码及教程方法。可以轻松管理和使用API接口。 安装步骤 打开config/database.php配置数据库信息导入数据库data.sql设置运行目录为/public伪静态设置think PHP后台地址/admin/login.html 账号&#xff1a;adm…

【算法与数据结构】669、LeetCode修剪二叉搜索树

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;450、LeetCode删除二叉搜索树中的节点两道题的思路几乎是一样的&#xff0c;只不过终止条件和单层递归…

#循循渐进学51单片机#定时器与数码管#not.4

1、熟练掌握单片机定时器的原理和应用方法。 1&#xff09;时钟周期&#xff1a;单片机时序中的最小单位&#xff0c;具体计算的方法就是时钟源分之一。 2&#xff09;机器周期&#xff1a;我们的单片机完成一个操作的最短时间。 3)定时器&#xff1a;打开定时器“储存寄存器…

前端-layui动态渲染表格行列与复杂表头合并

说在前面&#xff1a; 最近一直在用layui处理表格 写的有些代码感觉还挺有用的&#xff0c;顺便记录下来方便以后查看使用&#xff1b; HTML处代码 拿到id 渲染位置表格 <div class"layui-table-body salaryTable"><table class"layui-table" i…

Faunadb入门

Faunadb和google spanner都属于云分布式数据库天然支持分片(无需做分表分库操作&#xff0c;一库搞定&#xff0c;当然价格另说)&#xff0c;国内的也有比如TiDB Oceanbase等 本文使用java语言&#xff0c;其他语言可以跳过&#xff1b;有想直接使用的可以参考(无法访问外网&…

uniapp开发h5,解决项目启动时,Network: unavailable问题

网上搜了很多&#xff0c;发现都说是要禁用掉电脑多余的网卡&#xff0c;这方法我试了没有好&#xff0c;不晓得为啥子&#xff0c;之后在网上看&#xff0c;uniapp的devServer vue2的话对标的就是webpack4的devserver&#xff08;除了复杂的函数配置项&#xff09;&#xff0c…

牛客: BM5 合并k个已排序的链表

牛客: BM5 合并k个已排序的链表 文章目录 牛客: BM5 合并k个已排序的链表题目描述题解思路题解代码 题目描述 题解思路 合并链表数组中的前两条链表,直到链表数组的长度为一, 返回这个唯一的链表 题解代码 package main/** type ListNode struct{* Val int* Next *ListN…

一个十分好用且美观的vue3后台管理系统框架

给大家推荐一个十分好用且美观的vue3后台管理系统框架 码云地址 项目完全开源&#xff0c;另外还给想学习框架搭建的同学&#xff0c;准备了学习视频&#xff0c;价格美丽&#xff0c;保证物美价廉。 试看视频 项目技术栈 Vue3Vite4Typescript5piniaelement plusUnocsspnp…

Git的基本操作:分支管理

8 分支管理 这里主要体现的git的功能的分离&#xff0c;这才是真正的git吧。每一个分支都是一个单独的可以分离的工作单位。每个用户可以建立不同的分支进行工作&#xff0c;最终提交到同一个开发分支上。一个用户可以建立不同的分支实现不同的功能&#xff0c;最终提交到同一…

CPU的三级缓存

CPU缓存&#xff08;Cache Memory&#xff09;是位于CPU与内存之间的临时存储器&#xff0c;它的容量比内存小的多但是交换速度却比内存要快得多。高速缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾&#xff0c;因为CPU运算速度要比内存读写速度快很多&#…

Python语言学习实战-内置函数filter()的使用(附源码和实现效果)

实现功能 filter()函数是Python的内置函数之一&#xff0c;用于过滤序列中的元素。它接受两个参数&#xff1a;一个是函数&#xff0c;用于判断每个元素是否符合条件&#xff1b;另一个是可迭代对象&#xff0c;包含要过滤的元素。filter()函数返回一个迭代器&#xff0c;其中包…

Spring MVC里的DispatchServlet(结合Spring官网翻译)

Spring MVC里的DispatchServlet 前言1.Spring Web MVC1.1 DispatcherServlet&#xff08;中央调度器&#xff09;1.1.1 Context Hierarchy&#xff08;上下文层次结构&#xff09;1.1.2 Special Bean Types&#xff08;特定的bean类型&#xff09;1.1.3 Web MVC Config1.1.4 Se…