【Sprig Boot整合Web开发 上】

【Sprig Boot整合Web开发 上】

一、返回JSON数据

1、默认实现

​ JSON是目前主流的前后端数据传输方式,SpringMVC中使用消息转换器HttpMessageConverter对JSON的转换提供了很好的支持,在Spring Boot中更进一步,对相关配置做了更进一步的简化。

在默认的web依赖下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

jackson-databind作为JSON处理器,此时不需要添加额外的JSON处理器就能返回一段JSON

  • 创建Book实体类
package com.darkerg.chapter4.pojo;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;

import java.util.Date;

@Data
public class Book {
    private String name;
    private String author;
    @JsonIgnore
    private Float price;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date publicationDate;
    
}
@JsonIgnore注解

作用:在json序列化时将pojo中的一些属性忽略掉,标记在属性或者方法上,返回的json数据即不包含该属性。

实体类字段中添加@JsonFormat注解(),返回 yyyy-MM-dd  HH:mm:ss  时间格式
  • 创建BookController,返回Book对象。
package com.darkerg.chapter4.controller;

import com.darkerg.chapter4.pojo.Book;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;

@Controller
public class BookController {

    @GetMapping("/book")
    @ResponseBody
    public Book book(){
        Book book = new Book();
        book.setAuthor("罗贯中");
        book.setName("三国演义");
        book.setPrice(30f);
        book.setPublicationDate(new Date());

        return book;
    }
}

@ResponseBody详解:

image-20210905094424113

  • 启动

image-20210905094523615

  • 总结

    这是Spring Boot自带的JSON处理方式,如果采用这种方式,那么对于字段忽略、日期格式化等常见需求都可以通过注解来解决。

    这是通过Spring中默认提供的MappingJackson2HttpMessageConverter来实现的。

2、自定义转换器

①使用Gson

​ Gson是Google的一个开源JSON解析框架。使用Gson,需要先除去默认的jackson-databind,然后加入Gson依赖,代码如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
</dependency>

​ Spring Boot中默认提供了Gson的自动转换类GsonHttpMessageConvertersConfiguration,因此Gson添加依赖后,可以像使用jackson-databind那样直接使用Gson。但是在Gson进行转换时,如果想对日期数据进行格式化,那么还需要开发者自定义HttpMessageConverter。可通过下面的方式:

  • 首先看一下GsonHttpMessageConvertersConfiguration的一段源码:
@Bean
@ConditionalOnMissingBean
public GsonHttpMessageConverter gsonHttpMessageConverter(Gson gson){
    GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
    converter.setGson(gson);
    return converter;
}

​ @ConditionalOnMissingBean注解表示当项目中没有提供GsonHttpMessageConverter时才会使用默认的GsonHttpMessageConverter,所以开发者只需要提供一个GsonHttpMessageConverter即可,代码如下:

package com.darkerg.chapter4.config;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.GsonHttpMessageConverter;

import java.lang.reflect.Modifier;

@Configuration
public class GsonConfig {

    @Bean
    GsonHttpMessageConverter gosnHttpMessageConverter() {
        GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
        GsonBuilder builder = new GsonBuilder();
        builder.setDateFormat("yyyy-MM-dd");
        builder.excludeFieldsWithModifiers(Modifier.PROTECTED);
        Gson gson = builder.create();
        converter.setGson(gson);
        return converter;
    }

}

代码解释:

  • 开发者自己提供一个GsonHttpMessageConverter的实例。
  • 设置Gson解析时日期的格式。
  • 设置Gson解析时修饰符为protected的字段被过滤掉。
  • 创建Gson对象放入GsonHttpMessageConverter的实例中并返回converter。

此时,将Book类中的price字段修饰符改为protected,代码如下:

package com.darkerg.chapter4.pojo;

import lombok.Data;

import java.util.Date;

@Data
public class Book {
    private String name;
    private String author;
    protected Float price;
    private Date publicationDate;

}

image-20210905100834058

②使用fastjson

​ fastjson是阿里巴巴的一个开源JSON解析框架,不同于Gson,fastjson集成后并不能马上使用,需要开发者提供相应的HttpMessageConverter后才能使用,步骤如下:

  • 依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.76</version>
</dependency>
  • 配置fastjson的HttpMessageConverter
package com.darkerg.chapter4.config;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.nio.charset.Charset;

@Configuration
public class MyFastJsonConfig {

    @Bean
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter(){
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setDateFormat("yyyy-MM-dd");
        config.setCharset(Charset.forName("UTF-8"));
        config.setSerializerFeatures(
                SerializerFeature.WriteClassName,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.PrettyFormat,
                SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteNullStringAsEmpty
        );
        converter.setFastJsonConfig(config);
        return converter;
    }
}

代码解释:

  • 自定义MyFastJsonConfig,完成对FastJsonHttpMessageConverterBean的提供。
  • 分别配置了JSON解析过程的一些细节,例如日期格式,数据编码、是否在生成的JSON中输出类名、是否输出value为null的数据、生成的JSON格式化、空集合输出[]而非null,空字符串输出""而非null等基本配置

MyFastJsonConfig配置完成后,还需要配置响应编码,否则返回的JSON中文会乱码,在application.properties中添加如下配置:

server.servlet.encoding.force-response=true

​ 对于FastJsonHttpMessageConverter的配置,除了上面这种方式之外,还有另一种方式。

​ 在Spinrg Boot项目中,当开发者引入spring-boot-starter-web依赖之后,该依赖又依赖了spring-boot-autoconfigure,在这个自动化配置中,有一个WebMvcAutoConfiguration类提供了对SpringMVC的最基本的配置,如果某一项自动化配置不满足开发需求,开发者可以针对该项目自定义配置,只需要实现WebMvcConfigurer接口即可(在Spring5.0之前是通过继承WebMvcConfigurerAdapter类来实现的),代码如下:

image-20210905102944098

package com.darkerg.chapter4.config;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.Charset;
import java.util.List;

public class MyWebMvcConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setDateFormat("yyyy-MM-dd");
        config.setCharset(Charset.forName("UTF-8"));
        config.setSerializerFeatures(
                SerializerFeature.WriteClassName,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.PrettyFormat,
                SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteNullStringAsEmpty
        );
        converter.setFastJsonConfig(config);
        converters.add(converter);
    }
}

二、静态资源访问

在SpringMVC中,对于静态资源都需要开发者手动配置静态资源过滤。SpringBoot中对此也提供了自动化配置,可以简化静态资源过滤配置。

1、默认策略

​ Spring Boot中对于SpringMVC的自动化配置都在WebMvcAutoConfiguration类中。

  • 在WebMvcAutoConfiguration类中有一个静态内部类WebMvcAutoConfigurationAdapter,实现了WebMvcConfigurer接口。
  • WebMvcConfigurer接口中有一个方法addResourceHandlers是用来配置静态资源过滤的。
  • 方法在WebMvcAutoConfigurationAdapter类中得到了实现,如下:

image-20210905135418465

Spring Boot在这里进行了默认的静态资源过滤配置,其中staticPathPattern默认定义在WebMvcProperties中,定义内容如下:

image-20210905135909184

WebProperties类中的内部类Resources中的getStaticLocations()可以获取到的默认静态资源位置定义在Resources中:

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};

综上可以看到,Spring Boot默认会过滤所有的静态资源,而静态资源位置一共有4个(上面的四个),优先级也会依次降低。

image-20210905140642976

如果使用IDEA创建Spring Boot项目,就会默认创建出classpath:/static/目录,静态资源一般放在这个目录下即可。

2、自定义策略

①在配置文件中定义

​ 可以在application.properties中直接定义过滤规则和静态资源位置,代码如下:

spring.mvc.static-path-pattern=/static/**
spring.web.resources.static-locations=classpath:/static/

​ 过滤规则为/static/**,静态资源位置为classpath:/static/。

​ 重新启动项目,在浏览器中输入“http://localhost:8080/static/p1.png,即可看到classpath:/static/目录下的资源。

②Java编码定义

​ 只需要实现WebMvcConfigurer接口即可,然后实现该接口的addResourceHandlers方法:代码如下:

package com.darkerg.chapter4.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {

    public void addResourceHandlers(ResourceHandlerRegistry registry){
        registry
                .addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");
    }

}

三、文件上传

​ SpringMVC对文件上传做了简化,在Spring Boot中更进一步简化。

​ Java中的文件上传一共涉及两个组件,一个是CommonsMultipartResolver,另一个是StandardServletMultipartResolver,其中CommonsMultipartResolver使用commons-fileupload来处理multipart请求,而StandardServletMultipartResolver则是基于Servlet3.0来处理multipart请求的,因此若使用StandardServletMultipartResolver,则不需要添加额外的jar包。Tomcat7.0开始就支持Servlet3.0了。因此可以直接使用StandardServletMultipartResolver。

​ 下面贴部分Spring Boot提供的文件上传自动化配置类MultipartAutoConfiguration的源码:

image-20210905142021418

可以看出,如果开发者没有提供MultipartResolver,那么默认才用的MultipartResolver就是StandardServletMultipartResolver。因此,在Spring Boot中上传文件甚至可以做到零配置。

1、单文件上传

  • 在resources目录下的static目录中创建一个upload.html文件,内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="uploadFile" value="请选择文件">
    <input type="submit" value="上传">
</form>

</body>
</html>
  • 接着创建文件上传的处理接口
package com.darkerg.uploadfile.controller;


import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;


@RestController
public class FileUploadController {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");

    @PostMapping("/upload")
    public String upload(MultipartFile uploadFile, HttpServletRequest req){
        String realPath = req.getSession().getServletContext().getRealPath("/uploadFile/");
        //调试查看本地存储地址
        System.out.println(realPath);
        String format = sdf.format(new Date());
        File folder = new File(realPath + format);
        if (!folder.isDirectory()){
            folder.mkdirs();
        }
        String oldName = uploadFile.getOriginalFilename();
        String newName = UUID.randomUUID().toString()+
                oldName.substring(oldName.lastIndexOf("."),oldName.length());
        try {
            uploadFile.transferTo(new File(folder,newName));
            String filepath = req.getScheme() + "://" + req.getServerName() + ":" +
                    req.getServerPort() + "/uploadFile/" + format + newName;
            return filepath;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "上传失败";
    }
}

解释:

  • 规划上传文件的保存路径为项目运行目录下的uploadFile文件夹,并在文件夹中通过对日期对所上传的文件归类保存。
  • 给上传的文件重命名,避免文件重名。
  • 文件保存操作
  • 生成上传文件的访问路径,并将访问路径返回。

image-20210905143351418

#是否开启文件上传支持,默认为true
spring.servlet.multipart.enabled=true
#文件写入磁盘的阈值,默认为0
spring.servlet.multipart.file-size-threshold=100
#文件上传的临时保存位置
spring.servlet.multipart.location=C:\\Users\\darkerg\\Desktop\\temp
#上传文件单个文件的最大大小,默认为1MB
spring.servlet.multipart.max-file-size=10MB
#多文件上传时文件的总大小
spring.servlet.multipart.max-request-size=50MB
#文件是否延迟解析,默认为false
spring.servlet.multipart.resolve-lazily=false

image-20210905155443692

2、多文件上传

​ 多文件上传和单文件上传基本一致,首先修改HTML文件,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="uploadFiles" value="请选择文件">
    <input type="submit" value="上传">
</form>

</body>
</html>
package com.darkerg.uploadfile.controller;


import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;


@RestController
public class FileUploadController {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");

    @PostMapping("/upload")
    public String upload(MultipartFile[] uploadFiles, HttpServletRequest req){

        for (MultipartFile uploadFile : uploadFiles) {
            String s = uploadSingle(uploadFile, req);
            return s;
        }
        return "上传失败";
    }
    public String uploadSingle(MultipartFile uploadFile, HttpServletRequest req){
        String realPath = req.getSession().getServletContext().getRealPath("/uploadFile/");
        System.out.println(realPath);
        String format = sdf.format(new Date());
        File folder = new File(realPath + format);
        if (!folder.isDirectory()){
            folder.mkdirs();
        }
        String oldName = uploadFile.getOriginalFilename();
        String newName = UUID.randomUUID().toString()+
                oldName.substring(oldName.lastIndexOf("."),oldName.length());
        try {
            uploadFile.transferTo(new File(folder,newName));
            String filepath = req.getScheme() + "://" + req.getServerName() + ":" +
                    req.getServerPort() + "/uploadFile/" + format + newName;
            return filepath;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "上传失败";
    }

}

四、@ControllerAdvice

​ 顾名思义,@ControllerAdvice就是@Controller的增强版。@ControllerAdvice主要用来处理全局数据,一般搭配@ExceptionHandler、@ModelAttribute以及@InitBinder使用。

1、全局异常处理

image-20210905160732132

image-20210905160815873

image-20210905160841764

2、添加全局数据

​ @ControllerAdvice是一个全局数据处理组件,因此也可以在@ControllerAdvice中配置全局数据,使用@ModelAttribute注解进行配置,代码如下:

import org.springframework.web.bind.annotation.ModelAttribute;

import java.util.HashMap;
import java.util.Map;

public class GlobalConfig {
    @ModelAttribute(value = "info")
    public Map<String ,String> userInfo(){
        HashMap<String, String> map = new HashMap<>();
        map.put("username","罗贯中");
        map.put("gender","男");
        return map;
    }

}

代码解释:

  • 在全局配置中添加userInfo方法,返回一个map。该方法有一个注解@ModelAttribute,其中的value属性表示这条返回数据的key,而方法的返回值是返回数据的valu。
  • 此时在任意请求的Controller中,通过方法参数中的Model都可以获取info的数据。

Controller示例代码:

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

@Controller
public class TestController {

    @GetMapping("/hello")
    @ResponseBody
    public void hello(Model model){
        Map<String, Object> map = model.asMap();
        Set<String> keySet = map.keySet();
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()){
            String key = iterator.next();
            Object value = map.get(key);
            System.out.println(key + ">>>>" + value);
        }

    }

}

3、请求参数预处理

​ @ControllerAdvice结合@InitBinder还能实现请求参数预处理,即将表单中的数据绑定到实体类上时进行一些额外处理。

image-20210905162012073

image-20210905162047351

image-20210905162056066

五、自定义错误页

​ Spring Boot在返回错误信息时候不一定返回HTML页面,而是根据实际情况返回HTML或者JSON。

​ 错误默认是由BasicErrorController来处理的

1、简单配置

  • 在resources/static目录下创建error目录
  • 在error目录中创建错误展示页面
  • 自动配置

image-20210905162658352

通过Thymeleaf创建

image-20210905163340369

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<table border="1">
    <tr>
        <td>timestamp</td>
        <td th:text="${timestamp}"></td>
    </tr>
    <tr>
        <td>status</td>
        <td th:text="${status}"></td>
    </tr>
    <tr>
        <td>error</td>
        <td th:text="${error}"></td>
    </tr>
    <tr>
        <td>message</td>
        <td th:text="${message}"></td>
    </tr>
    <tr>
        <td>path</td>
        <td th:text="${path}"></td>
    </tr>

</table>

</body>
</html>

image-20210905163405266

2、自定义Error视图

​ Error视图是展示给用户的页面。

  • 在resources/templates目录下提供errorPage.html视图:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>errorPage</h3>
<table border="1">
    <tr>
        <td>custommsg</td>
        <td th:text="${custommsg}"></td>
    </tr>
    <tr>
        <td>timestamp</td>
        <td th:text="${timestamp}"></td>
    </tr>
    <tr>
        <td>status</td>
        <td th:text="${status}"></td>
    </tr>
    <tr>
        <td>error</td>
        <td th:text="${error}"></td>
    </tr>
    <tr>
        <td>message</td>
        <td th:text="${message}"></td>
    </tr>
    <tr>
        <td>path</td>
        <td th:text="${path}"></td>
    </tr>

</table>

</body>
</html>

​ 在errorPage.html中,除了展示Spring Boot提供的5条Error信息外,也展示了开发者自定义的Error信息。此时无论发生4xx的错误还是5xx的错误,都会来到errorPage.html页面。

3、完全自定义

​ SpringBoot提供BasicErrorController作为默认的ErrorController,开发者可以提供自己的ErrorController:

  • 实现ErrorController接口
  • 继承BasicErrorControler
https://blog.csdn.net/lizhiqiang1217/article/details/91357576

六、CORS支持

​ CORS(Cross0Origin Resource Sharing)是W3C指定的一种跨域资源共享技术标准,其目的就是为了了解决前端的跨域请求。

image-20210905203501653

image-20210905203526401

image-20210905203636821

image-20210905203647259

image-20210905203654288

1、创建控制器

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/book")
public class BookController {
    
    @PostMapping("/")
    public String addBook(String name){
        return "receive:"+name;
    }
    
    @DeleteMapping("/{id}")
    public String deleteBookById(@PathVariable Long id){
        return String.valueOf(id);
    }
    
}

添加和删除接口。

2、配置跨域

①在响应的请求方法上加注解:

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/book")
public class BookController {

    @PostMapping("/")
    @CrossOrigin(value = "http://localhost:8081")
    public String addBook(String name){
        return "receive:"+name;
    }

    @DeleteMapping("/{id}")
    @CrossOrigin(value = "http://localhost:8081"
                ,maxAge = 1800,allowedHeaders = "*")
    public String deleteBookById(@PathVariable Long id){
        return String.valueOf(id);
    }

}

代码解释:

  • @CrossOrigin中的value表示支持的域,这里表示来自http://localhost:8081域的请求时支持跨域的。
  • maxAge表示探测请求的有效期,对于DELETE、PUT请求等会先发送探测请求,探测请求不需要每次都发送,可以配置一个有效期,默认是1800秒,即30分钟。
  • allowedHeaders表示允许的请求头,*所有。

②全局配置

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    
    public void addCorsMappings(CorsRegistry registry){
        registry.addMapping("/book/**")
                .allowedHeaders("*")
                .allowedMethods("*")
                .maxAge(1800)
                .allowedOrigins("http://localhost:8081");
    }
}

image-20210905204650771

3、测试

在resources/static目录下,加入jquery.js,再在resources/static目录下创建一个index.html文件,内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="jquery-3.2.1.js"></script>
</head>
<body>

<div id="contentDiv"></div>
<div id="deleteResult"></div>
<input type="button" value="提交数据" onclick="postData()"><br>
<input type="button" value="删除数据" onclick="deleteData()"><br>
<input type="button" value="获取数据" onclick="getData()"><br>
<script>
    function getData() {
        $.ajax({
            url:'http://localhost:8080/bs',
            type:'get',
            success:function (msg) {
                $("#contentDiv").html(msg);
            }
        })
    }
    function deleteData() {
        $.ajax({
            url:'http://localhost:8080/book/99',
            type:'delete',
            success:function (msg) {
                $("#deleteResult").html(msg);
            }
        })
    }
    function postData() {
        $.ajax({
            url:'http://localhost:8080/book',
            type:'post',
            data:{name:'三国演义'},
            success:function (msg) {
                $("#contentDiv").html(msg);
            }
        })
    }
</script>

</body>
</html>

两个普通的Ajax都发送了一个跨域请求。然后将项目的端口修改为8081

server.port=8081

image-20210905205531359

posted @ 2021-09-05 21:04  DarkerG  阅读(42)  评论(0编辑  收藏  举报