SpringMVC快速上手

便利之处

springMVC在web项目中主要的作用就是对请求和响应的处理;

处理请求

原先我们需要获取前端发送的简单参数需要通过httpServletRequest.getParameter来获取

java 复制代码
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Integer pageNumber = Integer.valueOf(req.getParameter("pageNumber"));
        Integer pageSize = Integer.valueOf(req.getParameter("pageSize"));
        String keyword = req.getParameter("keyword");
        ResponseResult<List<Owner>> result = ownerService.pages(pageNumber, pageSize, keyword);
        asyResponse(result, resp);
    }

对于复杂的数据类型比如json 数据需要通过ObjectMapper对象进行获取

java 复制代码
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ObjectMapper objectMapper = new ObjectMapper();
   		Owner owner = objectMapper.readValue(req.getInputStream(), Owner.class);
        ResponseResult responseResult = ownerService.add(owner);
        asyResponse(responseResult, resp);
    }

以上原始的方法太过于复杂,springMVC提供了更为简单的方式。

简单的get请求可以直接和方法的形参直接映射,只需要形参名字和请求带的参数名字一致;

甚至可以直接通过 @PathVariable来接收多个参数

对于json 数据也可以通过 @RequestBody轻松解决

处理响应

原始的javaweb处理响应十分不便

1)需要通过response.setContentType来设置数据格式类型

2)需要通过ObjectMapper将数据转成string形式才能发送,这一步也需要我们手动完成

java 复制代码
@SneakyThrows
    protected void asyResponse(ResponseResult result, HttpServletResponse response) {
        response.setContentType("application/json;charset=utf-8");
        objectMapper.registerModule(new JavaTimeModule());
        PrintWriter writer = response.getWriter();
        writer.write(objectMapper.writeValueAsString(result));
    }

springMVC对于以上步骤都进行了封装处理

当我们需要将数据传回前端时,只需要直接return,不需要关心数据类型的转换

java 复制代码
 @RequestMapping("/list")
    private ResponseResult list() {
        ResponseResult result = studentService.list();
        return result;
    }

配置文件

pom.xml文件------------各种依赖

XML 复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.example</groupId>
        <artifactId>J10_Project02</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.wngz</groupId>
    <artifactId>SpringMvc_Case</artifactId>
    <packaging>war</packaging>
    <name>SpringMvc_Case Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <!--scope范围,表示这个jar只能在测试环境中使用,即只能在test文件夹中使用-->
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>
<!--        springMVC的框架支持-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.25</version>
        </dependency>
<!--        javaWeb的基础支持,
            为了防止在其他环境运行时和tomcat自带的servlet冲突,scope设置为只有在开发环境适用-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <!--表示所使用的jar仅仅只是在开发环境中使用,发布时不使用-->
            <scope>provided</scope>
        </dependency>
<!--        页面渲染api-->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>
<!--        读取和返回json格式的依赖支持-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>2.14.2</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>SpringMvc_Case</finalName>
    </build>
</project>

web.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
<!--    编码过滤器,过滤器要在DispatcherServlet前面配置,不然不生效-->
<!--    过滤器本质也是servlet,配置方法和servlet一样-->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
        <!--  <url-pattern>/</url-pattern>

    当配置 / 的时候,会匹配到路径型的如:/login,而不会匹配到后缀型的,如:/login.jsp
    当经过视图解析器返回jsp视图的时候,就不会进入到DispatcherServlet
    为什么jsp的请求不会命中到DispatcherServlet呢?
    因为servlet容器内的jsp的servlet将会被调用,此servlet已经默认映射在了*.jsp上,这样就不会经过DispatcherServlet,但是DispatcherServlet它能拦截到静态的资源

    /* 会匹配到所有的url,路径型和后缀型,包括静态资源,当经过视图解析器返回jsp视图的时候,就会进入到DispatcherServlet
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    所以在过滤的时候就要处理返回的.jsp-->
  
<!--    DispatcherServlet是springmvc的核心部分,
        负责请求的接收,model and view 的各种分配和调度,控制各种handle来完成请求和响应-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
<!--            springmvc依附于spring容器,因此需要告诉DispatcherServlet配置的spring容器的路径-->
<!--            如果spring配置容器在web.xml同路径下就不需要配置-->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
<!--        DispatcherServlet需要配置成tomcat启动时就加载完成,否则接收不到请求-->
        <load-on-startup>1</load-on-startup>
    </servlet>


    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

resources/springmvc.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <context:component-scan base-package="com.wngz.springmvc.controller"></context:component-scan>
<!--    表示静态资源有默认的servlet调用-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>
<!--    若没有该标签@Controller @RequestMapping("/hello")等标签不会生效-->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

特性

配置类WebMvcConfigurer

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyWrapHandler;

import javax.annotation.Nullable;
import java.util.List;
import java.util.Properties;

@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {

    // 配置路径匹配选项
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        // 默认情况下,使用后缀模式匹配(例如.html)和尾部斜杠匹配(/)。
        
        // 设置是否使用后缀模式匹配
        configurer.setUseSuffixPatternMatch(false);
        // 设置是否使用前缀模式匹配
        configurer.setUseTrailingSlashMatch(true);
    }

    // 配置内容协商选项
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        // 默认不启用参数内容协商,只根据请求的文件扩展名进行内容协商。

        // 启用参数内容协商
        configurer.favorParameter(true);
        // 设置参数名称
        configurer.parameterName("mediaType");
        // 启用扩展名内容协商
        configurer.favorPathExtension(true);
    }

    // 配置异步请求支持选项
    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        //默认超时时间为30秒。

        //使用默认的SimpleAsyncTaskExecutor作为异步任务执行器。

        // 设置默认的超时时间
        configurer.setDefaultTimeout(5000);
        // 添加自定义的异步任务执行器
        configurer.setTaskExecutor(new SimpleAsyncTaskExecutor());
    }

    // 配置默认Servlet处理选项
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        //默认情况下启用,映射所有不被@RequestMapping或其他处理器显式处理的请求到Servlet容器的默认Servlet。

        // 启用默认的Servlet处理
        configurer.enable();
    }

    // 添加格式化器和转换器
    @Override
    public void addFormatters(FormatterRegistry registry) {
        // 添加自定义的格式化器
        registry.addFormatter(new DateFormatter("yyyy-MM-dd"));
    }

    // 添加拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加自定义的拦截器
        registry.addInterceptor(new MyCustomInterceptor())
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/login");
    }

    // 添加资源处理器,用于静态资源的处理
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //默认情况下,没有显式添加静态资源处理器。静态资源通常直接由Servlet容器处理,例如Tomcat或Jetty。

        // 将所有 /static/** 的请求映射到 classpath:/static/ 目录下的资源
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");
    }

    // 添加跨域资源共享(CORS)映射
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //默认情况下不启用任何跨域资源共享配置,即不允许跨域请求。

        // 允许来自任意源的跨域请求
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowCredentials(true)
                .maxAge(3600);
    }

    // 添加视图控制器
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //默认情况下,没有添加任何视图控制器或视图解析器,因此所有视图解析工作交给视图解析链中的默认解析器处理。

        // 将 / 请求映射到 home.html 视图
        registry.addViewController("/").setViewName("home.html");
    }

    // 配置视图解析器
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        // 配置JSP视图解析器
        registry.jsp("/WEB-INF/views/", ".jsp");
    }

    // 添加自定义的参数解析器
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        // 添加自定义的参数解析器
        resolvers.add(new MyCustomArgumentResolver());
    }

    // 添加自定义的返回值处理器
    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
        // 添加自定义的返回值处理器
        handlers.add(new ResponseBodyWrapHandler());
    }

    // 配置消息转换器
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 添加自定义的消息转换器
        converters.add(new MappingJackson2HttpMessageConverter());
    }

    // 扩展消息转换器
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 在现有转换器之前添加自定义的消息转换器
        converters.add(0, new MyCustomMessageConverter());
    }

    // 配置异常解析器
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        // 添加简单的映射异常解析器
        SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
        Properties mappings = new Properties();
        mappings.setProperty("org.springframework.web.servlet.PageNotFound", "error-404");
        mappings.setProperty("org.springframework.dao.DataAccessException", "error-database");
        exceptionResolver.setExceptionMappings(mappings);
        resolvers.add(exceptionResolver);
    }

    // 扩展异常解析器
    @Override
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        // 在现有解析器之前添加自定义的异常解析器
        resolvers.add(0, new MyCustomExceptionResolver());
    }

    // 获取验证器
    @Nullable
    @Override
    public Validator getValidator() {
        // 返回自定义的验证器
        return new LocalValidatorFactoryBean();
    }

    // 获取消息码解析器
    @Nullable
    @Override
    public MessageCodesResolver getMessageCodesResolver() {
        // 返回自定义的消息码解析器
        return new DefaultMessageCodesResolver();
    }
}

拦截器 HandlerInterceptor

Filter和HandlerInterceptor的区别

Filter 定义:

Filter是Java Servlet规范的一部分,定义在javax.servlet.Filter接口中,用于对请求和响应进行过滤。

作用范围:

Filter可以对几乎所有的请求进行拦截,包括静态资源(如HTML、CSS、JavaScript文件)和动态资源(如Servlet、JSP)。

生命周期

Filter在整个应用程序启动时被初始化,并在应用程序关闭时销毁。每个请求都会调用Filter的doFilter方法。

用途

  • 认证和授权:检查用户是否登录,或者判断用户是否有权限访问某些资源。

  • 日志记录:记录请求的详细信息,例如IP地址、请求时间、请求参数等。

  • 压缩响应:在将响应发送回客户端之前对其进行压缩。

  • 字符编码:设置请求和响应的字符编码,确保正确处理不同的字符集。

  • 跨域资源共享(CORS):处理跨域请求,设置CORS相关的头信息。

示例:

java 复制代码
public class MyFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化代码
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 预处理代码
        System.out.println("Request received at MyFilter");
        
        chain.doFilter(request, response); // 将请求传递给下一个过滤器或目标资源

        // 后处理代码
        System.out.println("Response processed at MyFilter");
    }

    public void destroy() {
        // 销毁代码
    }
}

Spring MVC HandlerInterceptor 定义:

HandlerInterceptor是Spring框架的一部分,定义在org.springframework.web.servlet.HandlerInterceptor接口中,用于拦截处理器(controller)的执行过程。

作用范围

HandlerInterceptor主要用于拦截Spring MVC的处理器方法。它不拦截静态资源,除非特别配置。

生命周期

HandlerInterceptor的生命周期与Spring上下文相关。它们在Spring容器初始化时创建,并在容器关闭时销毁。

用途:

  • 预处理和后处理:在处理请求之前执行逻辑(例如身份验证),在处理请求之后但在生成视- 图之前执行逻辑(例如日志记录)。

  • 修改请求和响应:可以修改请求对象或响应对象中的数据。

  • 执行链控制:可以决定是否继续执行处理器链。

方法:

  • preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):在处理器方法执行之前调用。

  • postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):在处理器方法执行之后且在视图渲染之前调用。

  • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):在整个请求完成之后,即视图渲染之后调用。

示例:

java 复制代码
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("Request received at MyInterceptor");
        return true; // 返回true表示继续处理,返回false表示中断处理
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("Handler executed at MyInterceptor");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("Request completed at MyInterceptor");
    }
}
配置拦截器
java 复制代码
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {

    @Autowired
    JwtTokenTemplate jwtTokenTemplate;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        List<String> whiteList = new ArrayList<>();
        //白名单
        whiteList.add("/**/*.html");
        whiteList.add("/js/**/*");
        whiteList.add("/");
        whiteList.add("/user/login");
        whiteList.add("/code/generate");
        registry.addInterceptor(new TokenInterceptor(jwtTokenTemplate))
                .excludePathPatterns(whiteList);//添加白名单
    }
}

@Controller,@Service,@Reposity

作用和javaweb的@WebServlet一样

标记为一个webServlet

注意:若用该三种注解标注Servlet,需要有返回值的方法必须用@ResponseBody标注

java 复制代码
@Controller
@RequestMapping("/hello")
public class HelloController {
    public HelloController() {
        System.out.println("HelloController~~~");
    }
    //@RequestMapping默认为Get,Post请求都匹配
    @RequestMapping("/demo1")
    @ResponseBody
    //当需要返回值时,如果该Controller没有标记为RestController则需要加上@ResponseBody注解
    public String demo1() {
        return "woniu school";
    }
    @RequestMapping("/student")
    @ResponseBody
    public Student getStudent() {
        Student student = new Student();
        student.setName("张三");
        student.setAge(19);
        return student;
    }
}

@RestController

作用同样是标记为一个webServlet

不同的是使用该注解标记的Servlet类不需要在方法上标注 @ResponseBody

相当于 @Controller+@ResponseBody

java 复制代码
@RestController
@RequestMapping("/subject")
public class SubjectController {
    @Autowired
    private SubjectService subjectService;
    @RequestMapping("/list")
    private ResponseResult list() {
        ResponseResult result = subjectService.list();
        return result;
    }
}

@RequestMapping(请求路径匹配)

用作请求路径的匹配;

作用在类上标记该servlet映射的路径;

作用在方法上同样道理,

需要注意的是如果要访问servlet的具体方法时 ,url需要包含Servlet类上**@RequestMapping("/exam")** 的路径和方法上**@RequestMapping("/add")**的路径

java 复制代码
@RequestMapping("/exam")
public class ExamController {
    @Autowired
    private ExamService examService;
    
    @RequestMapping("/add")
    protected ResponseResult add(@RequestBody Exam exam) {
        ResponseResult result=examService.add(exam);
        return result;
    }
}

元注解:

@Target({ElementType.TYPE, ElementType.METHOD})=>可以作用在类和方法上

java 复制代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
}

@GetMapping

作用和@RequestMapping一样,不过只能标注在方法上

java 复制代码
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(
    method = {RequestMethod.GET}
)
public @interface GetMapping {
}

@PostMapping

作用和@RequestMapping一样,不过只能标注在方法上

java 复制代码
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(
    method = {RequestMethod.GET}

public @interface PostMapping {
}

@PutMapping

作用和@RequestMapping一样,不过只能标注在方法上

java 复制代码
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(
    method = {RequestMethod.GET}

public @interface PutMapping {
}

@DeleteMapping

作用和@RequestMapping一样,不过只能标注在方法上

java 复制代码
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(
    method = {RequestMethod.GET}

public @interface DeleteMapping {
}

接收前端发送的参数!!!

普通get请求(参数在url上)

单个参数

后端获取方式:在方法的参数列表中写上参数,当请求匹配到时可自动映射

注意:方法列表中的参数名要和get请求带的参数名要一一对应

前端:

java 复制代码
axios.get("/exam/remove?id=" + exam.id)

controller:

java 复制代码
 @RequestMapping("/remove")
    protected ResponseResult remove(Integer id) {
        ResponseResult result=examService.remove(id);
        return result;
    }
多个参数 @PathVariable

当通过get发送多个参数数据时,需要使用@PathVariable来指定

注意:@PathVariable指定的参数名要和路径的参数名保持一致

前端:

javascript 复制代码
 axios.get(`/owner/page/${this.pageNumber}/${this.pageSize}` )

controller:

java 复制代码
@GetMapping("/page/{pageNumber}/{pageSize}")
    public ResponseResult page(@PathVariable Integer pageNumber,
                               @PathVariable Integer pageSize) {
        PageHelper.startPage(pageNumber, pageSize);
        List<Owner> owners = ownerMapper.selectAll();
        PageInfo pageInfo = new PageInfo(owners);
        ResponseResult result = ResponseResult.success(pageInfo);
        return result;
    }

post发送复杂数据类型@RequestBody

前端:直接将json对象放在请求体中

javascript 复制代码
axios.post("/owner/add", this.owner4Add)

controller:

在方法参数列表中通过**@RequestBody**注解来标注接收复杂类型对象

java 复制代码
//接收单个JSON对象
@PostMapping("/add")
protected ResponseResult add(@RequestBody Owner owner) {
    ResponseResult responseResult = ownerService.add(owner);
    return responseResult;
}
//接收前端数组对象
@PostMapping("/batchDelete")
protected ResponseResult batchDelete(@RequestBody Integer[] ids) {
    ResponseResult responseResult = ownerService.batchDelete(ids);
    return responseResult;
}
相关推荐
Q_19284999066 分钟前
基于Spring Boot的建材租赁系统
java·spring boot·后端
鲨鱼辣椒不吃辣c8 分钟前
拦截器魔法:Spring MVC中的防重放守护者
java·spring·mvc
winks314 分钟前
Spring Task的使用
java·后端·spring
秋意钟25 分钟前
Spring新版本
java·后端·spring
椰椰椰耶27 分钟前
【文档搜索引擎】缓冲区优化和索引模块小结
java·spring·搜索引擎
mubeibeinv28 分钟前
项目搭建+图片(添加+图片)
java·服务器·前端
青莳吖30 分钟前
Java通过Map实现与SQL中的group by相同的逻辑
java·开发语言·sql
Buleall37 分钟前
期末考学C
java·开发语言
重生之绝世牛码39 分钟前
Java设计模式 —— 【结构型模式】外观模式详解
java·大数据·开发语言·设计模式·设计原则·外观模式
小蜗牛慢慢爬行1 小时前
有关异步场景的 10 大 Spring Boot 面试问题
java·开发语言·网络·spring boot·后端·spring·面试