likes
comments
collection
share

vue setup+springboot 前后端分离新手必备知识点与请求实践(delete/put/restful/图片上传)

作者站长头像
站长
· 阅读数 40

今天我要分享的是前后端分离技术,目前在很多大学里教的项目都是jsp+spring来做的,企业项目基本都是分离出来了,很多友友们不知道前后端怎么去对接,那么我这篇文章就是帮助小白一臂之力把这个流程给走通,如果已经了解过这篇文章也能够帮你好好复习。

这篇文章采用的技术栈是vue+springboot,主要讲解前端的请求怎么发,后端的api又是怎么样对接的。 在项目中又是如何产生交互的。

版本

  • springboot 2.7

  • vue 3.2

必备小知识

HTTP协议

HTTP协议是超文本传输协议的缩写,英文是Hyper Text Transfer Protocol。它是从WEB服务器传输超文本标记语言(HTML)到本地浏览器的传送协议,HTTP是一个基于TCP/IP通信协议来传递数据的协议,传输的数据可以为Html代码、图片、文字、文件。

这个协议就是按照一定的规则,向服务器要数据或发送数据,服务器也按照一定的规则回应数据。

vue setup+springboot 前后端分离新手必备知识点与请求实践(delete/put/restful/图片上传)

请求信息

例如这是一个http请求 由这个例子来引出HTTP的请求信息与响应格式

vue setup+springboot 前后端分离新手必备知识点与请求实践(delete/put/restful/图片上传)

  • 请求URL: URL后面的有一串?o=**这就是query参数。又比如?name=tina&age=18,query参数多个用&符号连接,query参数出现在url地址中

  • 请求方法: post方法 另外还有get put post delete options

  • 请求状态码: 200成功

状态码定义说明
1**信息接收到请求,继续处理
2**成功操作成功,理解和接受
3** 301/2 永久/临时重定向 304未修改(缓存)重定向为了完成请求,采取进一步措施
4**客户端错误请求的语法有错误或不能完全被满足
5** 503服务器不可用 500内部服务器服务端错误服务器错误

304 客户端告诉服务器我缓存里面有这个资源,而且拿这个编号和修改时间与服务器来比对一下,如果没有变化就304

302 临时重定向 (默认) 如果是get的重定向没有问题 ,如果是post两次重定向 表单的数据就没有了

307 重定向中保持原有的请求数据

  • Content-Length: 告诉服务器主体的长度
  • Content-Type: 请求类型(根据你传入的数据类型而定)
请求类型说明后端方法
application/x-www-form-urlencoded如果是post请求 会把请求参数转为query(键值对)参数,例如表单提交,浏览器会默认转为query@requestParamget/post
multipart/form-data文件上传@RequestParampost
application/jsonjson格式上传@requestbodypost

跨域问题

后端设置可请求的地址

前端不需要代理

@Configuration
public class WebMvcConfg implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //设置允许跨域的路径
        registry.addMapping("/**")
                //设置允许跨域请求的域名
                //当**Credentials为true时,**Origin不能为星号,需为具体的ip地址
                .allowedOrigins("http://localhost:3000", "http://127.0.0.1:8082")
                //是否允许证书 不再默认开启
                .allowCredentials(true)
                //设置允许的方法
                .allowedMethods("*")
                //跨域允许时间
                .maxAge(3600);
    }
}

前端配置代理

这种方法不太采取,安全性太低,建议大家第一种,这种方法了解即可

// vite.config.js
server: {
    // https: true,
    port:3000,
    proxy: {
      '/api': { // 配置需要代理的路径 --> 这里的意思是代理http://localhost:80/api/后的所有路由
        target: 'http://127.0.0.1:8080/', // 目标地址 --> 服务器地址
        changeOrigin: true, // 允许跨域
        ws: true,  // 允许websocket代理
        // 重写路径 --> 作用与vue配置pathRewrite作用相同
        rewrite: (path) => path.replace(/^/api/, "")
      }
    },
  },

axios请求实践

介绍完这些之后我们使用axios发起请求来实践一下 安装npm install axios axios的默认请求类型为json格式

封装请求方法

//request.js
import axios from "axios"; //引入axios
import { ElMessage } from "element-plus";
const service = axios.create({
    headers: {
       
    },
    baseURL: '/api', //接口访问的地址
    timeout: 10000,//超时
});
//请求前拦截
service.interceptors.request.use(config => {
    const token = localStorage.getItem("soul-token");
    if (token) {
        config.headers['Authorization'] = token;
    }
    return config;
}, (error) => {
    return Promise.reject(error);
});

// 响应后拦截
service.interceptors.response.use(response => {
    console.log(response);
    let data = response.data;
    if (data.code == 200) {
        return response.data;
    } else if (data.code == 501) {
        ElMessage.error('请重新登录');
        window.location.href = '/login';
    } else {
        ElMessage.error(response.data.message);
    }
}, error => {
    return Promise.reject(error);
})

export default service;

get请求

案例一
import request from '@/utils/request';

/**
 * 查询所有用户
 * @param {*} pageSize 
 * @param {*} pageNum 
 * @returns 
 */
export function requestUsersApi(pageSize, pageNum) {
    return request({
        url: '/admin/users',
        method: 'get',
        params: {
            pageSize,
            pageNum
        },
    })
}
/**
 * 查询所有用户
 * @param admin
 * @param pageNum
 * @param pageSize
 * @return
 */
@TokenCheck(roles = "admin")
@GetMapping("/users")
public BaseResponse<Page> selectAllUses(@LoginAdmin Admin admin, @RequestParam(value = "pageNum",defaultValue = "1") int pageNum , @RequestParam(value = "pageSize",defaultValue = "10") int pageSize){
    Page<User> page = new Page<>(pageNum, pageSize);
    return RespGenerator.returnOK(userService.selectAllUser(page));
}
案例二

不写@requestparam时,此时需要参数名称与query参数的名字与类型相同,否则就会为NUll或者报类型转换错误,那么如果前后端的参数名称不一样就可以采取@reqestparam 设置一个value值 如上图一样

vue setup+springboot 前后端分离新手必备知识点与请求实践(delete/put/restful/图片上传)

@GetMapping("/get")
public BaseResponse testgetMethod(String name,int age){
    return RespGenerator.returnOK("我收到数据了"+name+","+age);
}

post请求

发送post请求 默认为json格式 打开控制台,请求体与响应体的格式都为json 负荷就是传入服务器的参数 json格式 后端遇到@RequestBody解析为对象 对象的属性要与请求的json参数相同

vue setup+springboot 前后端分离新手必备知识点与请求实践(delete/put/restful/图片上传)

/**
 * 添加标签
 * @param {Object} tag 
 * @returns
 */
export function requestAddTag(tag) {
    return request({
        url: '/admin/tag/add',
        method: 'post',
        data:tag
    })
}
/**
 * 管理员添加标签
 */
@TokenCheck(roles = "admin")
@PostMapping("/admin/tag/add")
public BaseResponse addTags(@LoginAdmin Admin admin,@RequestBody Tags tags){
    log.info(tags.getTagName(),tags.getTypeId());
    tagsService.insertTags(tags);
    return RespGenerator.returnOK("添加成功");
}

put请求

put与post请求与服务器接收类似

/**
 * 修改话题
 * @param {Object} topic 
 * @returns 
 */
export function requestUpdateTopic(topic) {
    return request({
        url: '/admin/topic/update',
        method: 'put',
        data:topic
    })
}
@TokenCheck(roles = "admin")
@PutMapping("/admin/topic/update")
public BaseResponse<Object> updateTopic(@RequestBody  Topic topic){
    return RespGenerator.returnOK(topicService.updateById(topic));
}

delete请求

这里的删除与restful一起的 前面为路径 最后的/${id}为参数 服务器用@PathVariable接收参数 类型要匹配


/**
 * 删除标签
 * @param {*} id 
 * @returns 
 */
export function requestDelTag(id) {
    return request({
        url: `/admin/tag/del/${id}`,
        method: 'delete',
    })
}
/**
 * 删除
 * @param id
 * @return
 
 */
@DeleteMapping("/admin/topic/delete/{id}")
public BaseResponse<Object> deleteTopic(@PathVariable int id){
    return RespGenerator.returnOK(topicService.removeById(id));
}

resetful

restful在delete请求的时候也介绍过,主要就是通过/参数/参数的方法发起请求,后端@PathVariable接收,多个参数就加多个注解

图片上传 post

图片上传后端采用的是Multipart

 <el-upload class="avatar-uploader" action="/api/image/upload/1" :show-file-list="false"
                    :on-success="onSuccess" :on-preview="handlePreview" :limit="1">
                    <!-- <el-image style="width: 178px;height: 178px;" fit="fill" v-if="topicForm.cover"
                        :src="topicForm.cover"></el-image> -->
                    <Image v-if="topicForm.cover" :width="178" :height="178" fit="fill" :src="topicForm.cover"></Image>
                    <el-icon v-else class="avatar-uploader-icon">
                        <Plus />
                    </el-icon>
                </el-upload>

vue setup+springboot 前后端分离新手必备知识点与请求实践(delete/put/restful/图片上传)

图片上传后端

 @PostMapping("/image/upload/{type}")
    public BaseResponse<String> getImage(@RequestParam("file") MultipartFile file,@PathVariable Integer type) throws IOException {
        if (type==null){
            throw new CommonException("请求参数错误");
        }
        String subPath = "";
        if (type.equals(1)){
            subPath = "topic";
        }

        // 源文件名称
        final String originalFileName = file.getOriginalFilename();
        // 文件后缀
        final String suffix = originalFileName.substring(originalFileName.lastIndexOf(".")).toLowerCase();
        if (!WebTools.IMAGE_EXTENSIONS.contains(suffix)) {
            throw new CommonException("图片格式错误");
        }
        UUID uuid = UUID.randomUUID();
        final String newFileName = uuid + suffix;
        log.info("当前的路径为"+path+subPath+"/"+newFileName);
//        File f = new File(path+subPath + "/" + newFileName);
//        file.transferTo(f);
        FileUtils.copyInputStreamToFile(file.getInputStream(), new File(path+subPath+"/"+newFileName));
        return RespGenerator.returnOK(subPath+"/"+newFileName);
    }
转载自:https://juejin.cn/post/7270799920826466338
评论
请登录