欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringMVC開(kāi)發(fā)中十大常見(jiàn)問(wèn)題深度解析與解決方案

 更新時(shí)間:2025年06月19日 11:13:48   作者:程序員岳彬  
在Java Web開(kāi)發(fā)領(lǐng)域,SpringMVC作為一款主流的Web框架,憑借其強(qiáng)大的功能和便捷的開(kāi)發(fā)體驗(yàn)深受開(kāi)發(fā)者喜愛(ài),然而,在實(shí)際使用過(guò)程中,開(kāi)發(fā)者常常會(huì)遇到各種各樣的“坑”,本文將針對(duì)SpringMVC開(kāi)發(fā)中常見(jiàn)的十大問(wèn)題,需要的朋友可以參考下

引言

在Java Web開(kāi)發(fā)領(lǐng)域,SpringMVC作為一款主流的Web框架,憑借其強(qiáng)大的功能和便捷的開(kāi)發(fā)體驗(yàn)深受開(kāi)發(fā)者喜愛(ài)。然而,在實(shí)際使用過(guò)程中,開(kāi)發(fā)者常常會(huì)遇到各種各樣的“坑”。本文將針對(duì)SpringMVC開(kāi)發(fā)中常見(jiàn)的十大問(wèn)題,結(jié)合實(shí)際案例和代碼,深入剖析問(wèn)題產(chǎn)生的原因,并提供詳細(xì)的解決方案,幫助大家在開(kāi)發(fā)過(guò)程中少走彎路。

一、自定義異??偪床欢??是設(shè)計(jì)邏輯出了問(wèn)題嗎?

在SpringMVC項(xiàng)目中,當(dāng)業(yè)務(wù)邏輯變得復(fù)雜時(shí),使用自定義異??梢愿逦靥幚聿煌?lèi)型的錯(cuò)誤情況。但有時(shí)開(kāi)發(fā)者會(huì)發(fā)現(xiàn)自定義異常難以理解,這往往是因?yàn)楫惓TO(shè)計(jì)邏輯不夠清晰。

問(wèn)題場(chǎng)景

假設(shè)我們正在開(kāi)發(fā)一個(gè)電商系統(tǒng),在用戶(hù)下單時(shí)需要檢查庫(kù)存是否充足。當(dāng)庫(kù)存不足時(shí),希望拋出一個(gè)自定義的InsufficientStockException異常。但在實(shí)際調(diào)試過(guò)程中,發(fā)現(xiàn)異常信息混亂,難以定位問(wèn)題根源。

原因分析

自定義異常設(shè)計(jì)不規(guī)范,沒(méi)有合理繼承已有的異常體系,或者異常信息沒(méi)有包含足夠的上下文信息,導(dǎo)致在捕獲和處理異常時(shí)無(wú)法準(zhǔn)確判斷異常情況。

解決方案

  • 定義自定義異常類(lèi),合理繼承RuntimeExceptionException。例如:
// 繼承RuntimeException,定義庫(kù)存不足異常
public class InsufficientStockException extends RuntimeException {
    public InsufficientStockException(String message) {
        super(message);
    }
}
  • 在業(yè)務(wù)邏輯中使用自定義異常。以庫(kù)存檢查為例:
@Service
public class OrderService {
    private int stock = 10; // 模擬庫(kù)存數(shù)量

    public void placeOrder(int quantity) {
        if (quantity > stock) {
            // 庫(kù)存不足時(shí)拋出自定義異常
            throw new InsufficientStockException("庫(kù)存不足,無(wú)法下單");
        }
        // 正常下單邏輯
    }
}
  • 使用全局異常處理器統(tǒng)一處理異常,讓異常信息更清晰易讀。
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(InsufficientStockException.class)
    public String handleInsufficientStockException(InsufficientStockException e) {
        return "錯(cuò)誤信息:" + e.getMessage();
    }
}

二、自定義異常不生效?為何還在報(bào)500錯(cuò)誤?

開(kāi)發(fā)者定義好自定義異常并配置了異常處理器后,有時(shí)會(huì)發(fā)現(xiàn)自定義異常并沒(méi)有按照預(yù)期處理,頁(yè)面仍然顯示500錯(cuò)誤。

問(wèn)題場(chǎng)景

在上述電商系統(tǒng)中,配置好InsufficientStockException及其處理器后,下單時(shí)庫(kù)存不足依然顯示500錯(cuò)誤頁(yè)面。

原因分析

  • 異常處理器配置錯(cuò)誤,沒(méi)有被Spring容器正確掃描到。
  • 異常沒(méi)有被正確拋出,在拋出異常之前可能被其他代碼捕獲處理。
  • 全局異常處理器的優(yōu)先級(jí)問(wèn)題,其他優(yōu)先級(jí)更高的異常處理機(jī)制先攔截了異常。

解決方案

  • 確保異常處理器所在的類(lèi)被@RestControllerAdvice@ControllerAdvice注解標(biāo)注,并且所在的包被Spring容器掃描。例如,在Spring Boot項(xiàng)目的啟動(dòng)類(lèi)上添加@ComponentScan注解,掃描包含異常處理器的包:
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.demo"})
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
  • 檢查業(yè)務(wù)代碼中異常拋出的邏輯,確保異常能夠順利拋出到全局異常處理器。
  • 如果存在多個(gè)異常處理器,調(diào)整其優(yōu)先級(jí)??梢酝ㄟ^(guò)實(shí)現(xiàn)Ordered接口,重寫(xiě)getOrder方法來(lái)設(shè)置優(yōu)先級(jí),數(shù)值越小優(yōu)先級(jí)越高:
@RestControllerAdvice
public class GlobalExceptionHandler implements Ordered {
    @ExceptionHandler(InsufficientStockException.class)
    public String handleInsufficientStockException(InsufficientStockException e) {
        return "錯(cuò)誤信息:" + e.getMessage();
    }

    @Override
    public int getOrder() {
        return 1; // 設(shè)置優(yōu)先級(jí)
    }
}

三、時(shí)間格式轉(zhuǎn)換失???POST請(qǐng)求的“陷阱”注意到了嗎?

在處理包含日期時(shí)間類(lèi)型參數(shù)的POST請(qǐng)求時(shí),經(jīng)常會(huì)遇到時(shí)間格式轉(zhuǎn)換失敗的問(wèn)題。

問(wèn)題場(chǎng)景

前端通過(guò)POST請(qǐng)求發(fā)送一個(gè)包含日期時(shí)間字段的數(shù)據(jù)到后端,后端使用@RequestBody接收數(shù)據(jù)并綁定到實(shí)體類(lèi)中,但在轉(zhuǎn)換過(guò)程中出現(xiàn)Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date'錯(cuò)誤。

原因分析

  • 前端發(fā)送的日期時(shí)間格式與后端期望的格式不一致。
  • SpringMVC默認(rèn)的日期時(shí)間格式轉(zhuǎn)換配置不符合需求。
  • 在POST請(qǐng)求中,@RequestBody解析數(shù)據(jù)時(shí),對(duì)于日期時(shí)間類(lèi)型的轉(zhuǎn)換規(guī)則與GET請(qǐng)求不同,需要額外配置。

解決方案

  • 在實(shí)體類(lèi)的日期時(shí)間字段上使用@DateTimeFormat注解指定日期時(shí)間格式。例如:
public class Order {
    private Long id;
    // 指定日期時(shí)間格式為"yyyy-MM-dd HH:mm:ss"
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date orderTime;

    // 省略getter和setter方法
}
  • 配置SpringMVC的日期時(shí)間格式化。在Spring Boot項(xiàng)目中,可以在application.properties文件中添加以下配置:
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
  • 如果上述方法無(wú)效,可以自定義一個(gè)Converter來(lái)處理日期時(shí)間格式轉(zhuǎn)換。例如:
@Component
public class CustomDateConverter implements Converter<String, Date> {
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public Date convert(String source) {
        try {
            return sdf.parse(source);
        } catch (ParseException e) {
            throw new IllegalArgumentException("日期格式轉(zhuǎn)換失敗", e);
        }
    }
}

然后在配置類(lèi)中注冊(cè)這個(gè)轉(zhuǎn)換器:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private CustomDateConverter customDateConverter;

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(customDateConverter);
    }
}

四、調(diào)試斷點(diǎn)失效?是不是被多個(gè)Filter“攔截”了?

在調(diào)試SpringMVC項(xiàng)目時(shí),有時(shí)會(huì)發(fā)現(xiàn)設(shè)置的斷點(diǎn)無(wú)法進(jìn)入,導(dǎo)致調(diào)試工作無(wú)法正常進(jìn)行。

問(wèn)題場(chǎng)景

在控制器方法中設(shè)置了斷點(diǎn),啟動(dòng)調(diào)試模式后,請(qǐng)求到達(dá)該方法時(shí)斷點(diǎn)沒(méi)有生效,直接跳過(guò)執(zhí)行后續(xù)代碼。

原因分析

  • 項(xiàng)目中存在多個(gè)Filter,請(qǐng)求在到達(dá)控制器之前被其他Filter攔截處理,導(dǎo)致無(wú)法進(jìn)入斷點(diǎn)所在的控制器方法。
  • Filter的配置順序不合理,某些Filter在處理請(qǐng)求時(shí)消耗了請(qǐng)求資源,使得后續(xù)請(qǐng)求無(wú)法正常處理。
  • 斷點(diǎn)設(shè)置的位置存在問(wèn)題,例如在靜態(tài)方法或沒(méi)有被Spring容器管理的類(lèi)中設(shè)置斷點(diǎn)。

解決方案

  • 檢查項(xiàng)目中的Filter配置,確保沒(méi)有不必要的Filter攔截請(qǐng)求??梢酝ㄟ^(guò)在Filter的doFilter方法中添加日志輸出,查看請(qǐng)求是否經(jīng)過(guò)該Filter:
@Component
public class CustomFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("請(qǐng)求進(jìn)入CustomFilter");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("請(qǐng)求離開(kāi)CustomFilter");
    }

    @Override
    public void destroy() {
    }
}
  • 調(diào)整Filter的順序,確保關(guān)鍵的Filter在合適的位置執(zhí)行??梢酝ㄟ^(guò)實(shí)現(xiàn)Ordered接口,重寫(xiě)getOrder方法來(lái)設(shè)置Filter的執(zhí)行順序:
@Component
public class CustomFilter implements Filter, Ordered {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
    }

    @Override
    public int getOrder() {
        return 1; // 設(shè)置Filter執(zhí)行順序
    }
}
  • 確保斷點(diǎn)設(shè)置在被Spring容器管理的類(lèi)和方法中,并且方法不是靜態(tài)方法。

五、Request輸入流讀取后消失?響應(yīng)體處理遺漏了?

在處理請(qǐng)求和響應(yīng)時(shí),可能會(huì)遇到Request輸入流讀取一次后無(wú)法再次讀取,或者響應(yīng)體處理不當(dāng)導(dǎo)致數(shù)據(jù)丟失的問(wèn)題。

問(wèn)題場(chǎng)景

在一個(gè)需要多次讀取Request輸入流的場(chǎng)景中,第一次讀取后,后續(xù)讀取操作獲取到的輸入流為空。在處理響應(yīng)時(shí),發(fā)現(xiàn)響應(yīng)數(shù)據(jù)沒(méi)有按照預(yù)期輸出。

原因分析

  • HttpServletRequest的輸入流默認(rèn)只能讀取一次,讀取后流會(huì)被關(guān)閉或重置,導(dǎo)致后續(xù)無(wú)法再次讀取。
  • 在響應(yīng)體處理過(guò)程中,沒(méi)有正確設(shè)置響應(yīng)頭信息,或者沒(méi)有將數(shù)據(jù)正確寫(xiě)入響應(yīng)體。
  • 存在其他代碼在處理請(qǐng)求或響應(yīng)過(guò)程中,意外關(guān)閉了輸入流或響應(yīng)流。

解決方案

  • 自定義一個(gè)可以重復(fù)讀取的HttpServletRequest包裝類(lèi)。例如:
public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper {
    private final byte[] body;

    public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException {
        super(request);
        body = IOUtils.toByteArray(request.getInputStream());
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return bais.available() == 0;
            }

            @Override
            public boolean isReady() {
                return true;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }

            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
}

然后在Filter中使用這個(gè)包裝類(lèi)來(lái)替換原始的HttpServletRequest

@Component
public class RequestBodyCacheFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        CachedBodyHttpServletRequest cachedBodyHttpServletRequest = new CachedBodyHttpServletRequest(httpServletRequest);
        filterChain.doFilter(cachedBodyHttpServletRequest, servletResponse);
    }

    @Override
    public void destroy() {
    }
}
  • 正確處理響應(yīng)體,設(shè)置響應(yīng)頭信息并將數(shù)據(jù)寫(xiě)入響應(yīng)體。例如:
@RestController
public class HelloController {
    @GetMapping("/hello")
    public void hello(HttpServletResponse response) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        writer.write("{\"message\":\"Hello, World!\"}");
        writer.flush();
        writer.close();
    }
}
  • 檢查項(xiàng)目中所有涉及請(qǐng)求和響應(yīng)處理的代碼,確保沒(méi)有意外關(guān)閉輸入流或響應(yīng)流的操作。

六、參數(shù)綁定總出錯(cuò)?是類(lèi)型轉(zhuǎn)換規(guī)則沒(méi)吃透嗎?

在SpringMVC中進(jìn)行參數(shù)綁定時(shí),經(jīng)常會(huì)出現(xiàn)參數(shù)類(lèi)型轉(zhuǎn)換錯(cuò)誤的問(wèn)題,導(dǎo)致請(qǐng)求無(wú)法正確處理。

問(wèn)題場(chǎng)景

前端傳遞一個(gè)字符串類(lèi)型的參數(shù),后端控制器方法期望接收一個(gè)整數(shù)類(lèi)型的參數(shù),但在綁定過(guò)程中出現(xiàn)Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'錯(cuò)誤。

原因分析

  • 前端傳遞的參數(shù)類(lèi)型與后端控制器方法參數(shù)類(lèi)型不匹配,并且SpringMVC無(wú)法自動(dòng)進(jìn)行正確的類(lèi)型轉(zhuǎn)換。
  • 自定義的類(lèi)型轉(zhuǎn)換規(guī)則沒(méi)有生效,或者類(lèi)型轉(zhuǎn)換規(guī)則定義錯(cuò)誤。
  • 參數(shù)名稱(chēng)不一致,導(dǎo)致SpringMVC無(wú)法正確匹配參數(shù)。

解決方案

  • 確保前端傳遞的參數(shù)類(lèi)型與后端控制器方法參數(shù)類(lèi)型兼容,并且SpringMVC支持自動(dòng)類(lèi)型轉(zhuǎn)換。如果不支持自動(dòng)轉(zhuǎn)換,可以使用@RequestParam注解的required屬性設(shè)置為false,避免參數(shù)不存在時(shí)拋出異常:
@GetMapping("/user")
public String getUser(@RequestParam(value = "age", required = false) Integer age) {
    if (age == null) {
        return "年齡參數(shù)未傳遞";
    }
    return "用戶(hù)年齡為:" + age;
}
  • 對(duì)于復(fù)雜的類(lèi)型轉(zhuǎn)換,可以自定義類(lèi)型轉(zhuǎn)換器。例如,將字符串轉(zhuǎn)換為自定義的User對(duì)象:
public class User {
    private String name;
    private int age;

    // 省略getter和setter方法
}

@Component
public class UserConverter implements Converter<String, User> {
    @Override
    public User convert(String source) {
        String[] parts = source.split(",");
        User user = new User();
        user.setName(parts[0]);
        user.setAge(Integer.parseInt(parts[1]));
        return user;
    }
}

然后在配置類(lèi)中注冊(cè)這個(gè)轉(zhuǎn)換器:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private UserConverter userConverter;

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(userConverter);
    }
}
  • 檢查參數(shù)名稱(chēng)是否一致,確保前端傳遞的參數(shù)名與后端控制器方法中@RequestParam@RequestBody注解指定的參數(shù)名相同。

七、表單提交亂碼?編碼配置環(huán)節(jié)是否疏忽了?

在處理表單提交時(shí),有時(shí)會(huì)出現(xiàn)提交的數(shù)據(jù)在后端顯示為亂碼的情況。

問(wèn)題場(chǎng)景

用戶(hù)在前端表單中輸入中文內(nèi)容并提交,后端接收到的中文內(nèi)容顯示為亂碼。

原因分析

  • 前端表單的accept-charset屬性沒(méi)有正確設(shè)置,或者設(shè)置的編碼格式與后端不一致。
  • SpringMVC的編碼過(guò)濾器配置錯(cuò)誤,沒(méi)有對(duì)請(qǐng)求進(jìn)行正確的編碼處理。
  • 服務(wù)器的默認(rèn)編碼設(shè)置與項(xiàng)目要求的編碼不一致。

解決方案

  • 在前端表單中設(shè)置accept-charset屬性為UTF-8
<form action="/submit" method="post" accept-charset="UTF-8">
    <input type="text" name="username" />
    <input type="submit" value="提交" />
</form>
  • 在Spring Boot項(xiàng)目中,配置CharacterEncodingFilter來(lái)處理請(qǐng)求編碼。在application.properties文件中添加以下配置:
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
  • 如果上述配置無(wú)效,可以自定義一個(gè)Filter來(lái)處理編碼問(wèn)題:
@Component
public class EncodingFilter implements Filter {
    private static final String ENCODING = "UTF-8";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding(ENCODING);
        servletResponse.setCharacterEncoding(ENCODING);
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
    }
}
  • 檢查服務(wù)器的默認(rèn)編碼設(shè)置,確保與項(xiàng)目要求的編碼一致。例如,在Tomcat服務(wù)器中,可以在conf/server.xml文件中設(shè)置URIEncoding="UTF-8"
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           URIEncoding="UTF-8"/>

八、攔截器攔截范圍不對(duì)?匹配規(guī)則真的設(shè)置正確了?

在使用攔截器對(duì)請(qǐng)求進(jìn)行攔截處理時(shí),可能會(huì)出現(xiàn)攔截范圍不符合預(yù)期的問(wèn)題。

問(wèn)題場(chǎng)景

配置了一個(gè)攔截器用于攔截所有的用戶(hù)請(qǐng)求進(jìn)行權(quán)限驗(yàn)證,但某些請(qǐng)求卻沒(méi)有被攔截到;或者不應(yīng)該被攔截的請(qǐng)求反而被攔截了。

原因分析

  • 攔截器的addPathPatternsexcludePathPatterns方法設(shè)置的匹配規(guī)則不正確,沒(méi)有準(zhǔn)確覆蓋需要攔截或排除的請(qǐng)求路徑。
  • 攔截器的注冊(cè)順序問(wèn)題,導(dǎo)致部分請(qǐng)求在攔截器生效之前就已經(jīng)被處理。
  • 路徑匹配規(guī)則中使用的通配符(如***)理解錯(cuò)誤,導(dǎo)致匹配范圍不準(zhǔn)確。

解決方案

1. 定義攔截器類(lèi),實(shí)現(xiàn) HandlerInterceptor 接口,在 preHandle 方法中進(jìn)行攔截邏輯處理:

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class PermissionInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 簡(jiǎn)單示例:判斷請(qǐng)求中是否包含特定參數(shù)作為權(quán)限驗(yàn)證
        String authToken = request.getParameter("authToken");
        if (authToken == null || !"valid_token".equals(authToken)) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "權(quán)限不足");
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

2. 在配置類(lèi)中注冊(cè)攔截器,并設(shè)置攔截和排除路徑:

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

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new PermissionInterceptor())
               .addPathPatterns("/user/**") // 攔截所有以 /user/ 開(kāi)頭的請(qǐng)求
               .excludePathPatterns("/user/login", "/user/register"); // 排除登錄和注冊(cè)請(qǐng)求
    }
}

3. 若存在多個(gè)攔截器,通過(guò)實(shí)現(xiàn) Ordered 接口控制執(zhí)行順序:

import org.springframework.core.Ordered;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AnotherInterceptor implements HandlerInterceptor, Ordered {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 攔截邏輯
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }

    @Override
    public int getOrder() {
        return 2; // 數(shù)值越小優(yōu)先級(jí)越高,假設(shè) PermissionInterceptor 優(yōu)先級(jí)為 1
    }
}

并在配置類(lèi)中注冊(cè)該攔截器,這樣就能按順序執(zhí)行攔截邏輯。

九、視圖解析失?。磕0逡媾渲贸鰡?wèn)題了嗎?

在使用模板引擎(如 Thymeleaf、Freemarker)時(shí),常常會(huì)遇到視圖解析失敗的情況,頁(yè)面無(wú)法正確渲染。

問(wèn)題場(chǎng)景

在 SpringMVC 項(xiàng)目中集成了 Thymeleaf 模板引擎,控制器方法返回視圖名稱(chēng)后,頁(yè)面顯示 Whitelabel Error Page,提示找不到對(duì)應(yīng)的視圖。

原因分析

  • 模板引擎的依賴(lài)沒(méi)有正確引入,或者版本不兼容。
  • 模板引擎的配置不正確,如視圖前綴、后綴設(shè)置錯(cuò)誤,導(dǎo)致無(wú)法找到對(duì)應(yīng)的模板文件。
  • 模板文件的存放位置不符合配置要求,或者文件名拼寫(xiě)錯(cuò)誤。

解決方案

以 Thymeleaf 為例:

1. 確保在 pom.xml 文件中正確引入 Thymeleaf 依賴(lài):

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

2. 在 application.properties 文件中配置 Thymeleaf 的視圖前綴和后綴:

spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html

上述配置表示 Thymeleaf 會(huì)在 classpath:/templates/ 目錄下尋找模板文件,并且模板文件的后綴為 .html。

3. 確保模板文件存放在正確的目錄下,并且文件名與控制器返回的視圖名稱(chēng)一致。例如,控制器方法:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class IndexController {
    @GetMapping("/")
    public String index() {
        return "index"; // 返回視圖名稱(chēng)為 index,對(duì)應(yīng) templates 目錄下的 index.html 文件
    }
}

同時(shí),檢查模板文件中是否存在語(yǔ)法錯(cuò)誤,如標(biāo)簽閉合不正確、表達(dá)式錯(cuò)誤等,這些也可能導(dǎo)致視圖解析失敗。

十、跨域請(qǐng)求被拒?CORS 配置是否完整?

在前后端分離項(xiàng)目中,經(jīng)常會(huì)遇到跨域請(qǐng)求被拒絕的問(wèn)題,影響前后端數(shù)據(jù)交互。

問(wèn)題場(chǎng)景

前端發(fā)起請(qǐng)求到后端接口,瀏覽器控制臺(tái)提示 Access to XMLHttpRequest at 'xxx' from origin 'xxx' has been blocked by CORS policy 錯(cuò)誤,請(qǐng)求無(wú)法成功發(fā)送。

原因分析

  • 后端沒(méi)有配置 CORS(Cross-Origin Resource Sharing,跨域資源共享)相關(guān)規(guī)則,瀏覽器出于安全策略限制了跨域請(qǐng)求。
  • CORS 配置不完整,如只允許了部分請(qǐng)求方法、沒(méi)有設(shè)置允許攜帶憑證等,導(dǎo)致請(qǐng)求不符合跨域規(guī)則。

解決方案

方式一:使用 @CrossOrigin 注解

在控制器類(lèi)或方法上添加 @CrossOrigin 注解,簡(jiǎn)單快速地解決跨域問(wèn)題。例如:

import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@CrossOrigin(origins = "http://localhost:3000", allowedHeaders = "*", methods = {java.net.HttpURLConnection.HTTP_GET, java.net.HttpURLConnection.HTTP_POST})
public class ApiController {
    @GetMapping("/data")
    public String getData() {
        return "Hello, Cross-Origin Data";
    }
}

上述代碼中,@CrossOrigin 注解允許來(lái)自 http://localhost:3000 的請(qǐng)求,允許所有請(qǐng)求頭,支持 GET 和 POST 請(qǐng)求方法。

方式二:全局 CORS 配置

通過(guò)配置類(lèi)實(shí)現(xiàn) WebMvcConfigurer 接口,重寫(xiě) addCorsMappings 方法進(jìn)行全局 CORS 配置:

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 CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
               .allowedOrigins("http://localhost:3000")
               .allowedMethods("GET", "POST", "PUT", "DELETE")
               .allowedHeaders("*")
               .allowCredentials(true);
    }
}

這里配置了對(duì)所有請(qǐng)求路徑(/**)的跨域支持,允許來(lái)自 http://localhost:3000 的請(qǐng)求,支持 GET、POST、PUT、DELETE 等請(qǐng)求方法,允許所有請(qǐng)求頭,并且允許攜帶憑證(如 Cookie)。

通過(guò)以上對(duì) SpringMVC 開(kāi)發(fā)中十大常見(jiàn)問(wèn)題的詳細(xì)解析和解決方案介紹,希望能幫助你在實(shí)際開(kāi)發(fā)中順利避開(kāi)這些“坑”。

以上就是SpringMVC開(kāi)發(fā)中十大常見(jiàn)問(wèn)題深度解析與解決方案的詳細(xì)內(nèi)容,更多關(guān)于SpringMVC開(kāi)發(fā)常見(jiàn)問(wèn)題的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 如何通過(guò)Java生成一個(gè)隨機(jī)數(shù)

    如何通過(guò)Java生成一個(gè)隨機(jī)數(shù)

    當(dāng)我們需要在Java中生成隨機(jī)數(shù)時(shí),可以借助JDK中提供的Random類(lèi)來(lái)實(shí)現(xiàn),通過(guò)使用Random類(lèi),我們可以輕松地生成各種類(lèi)型的隨機(jī)數(shù),下面我們就來(lái)看看如何利用Random類(lèi)生成隨機(jī)數(shù)吧
    2023-09-09
  • Java程序測(cè)試上傳Maven工程代碼示例解析

    Java程序測(cè)試上傳Maven工程代碼示例解析

    這篇文章主要介紹了Java程序測(cè)試上傳Maven工程代碼示例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 在java中使用dom解析xml的示例分析

    在java中使用dom解析xml的示例分析

    本篇文章介紹了,在java中使用dom解析xml的示例分析。需要的朋友參考下
    2013-05-05
  • Eclipse添加servlet模板過(guò)程代碼詳解

    Eclipse添加servlet模板過(guò)程代碼詳解

    這篇文章主要介紹了Eclipse添加servlet模板過(guò)程代碼詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • java中for循環(huán)執(zhí)行的順序圖文詳析

    java中for循環(huán)執(zhí)行的順序圖文詳析

    關(guān)于java的for循環(huán)想必大家非常熟悉,它是java常用的語(yǔ)句之一,這篇文章主要給大家介紹了關(guān)于java中for循環(huán)執(zhí)行順序的相關(guān)資料,需要的朋友可以參考下
    2021-06-06
  • 淺析Java中的內(nèi)存泄漏

    淺析Java中的內(nèi)存泄漏

    這篇文章主要介紹了Java中的內(nèi)存泄漏,包括其基本概念和基本的預(yù)防措施,需要的朋友可以參考下
    2015-07-07
  • Java實(shí)現(xiàn)數(shù)據(jù)連接池Druid舉例

    Java實(shí)現(xiàn)數(shù)據(jù)連接池Druid舉例

    本文主要介紹了Java實(shí)現(xiàn)數(shù)據(jù)連接池Druid舉例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • java進(jìn)行文件讀寫(xiě)操作詳解

    java進(jìn)行文件讀寫(xiě)操作詳解

    這篇文章主要介紹了java進(jìn)行文件讀寫(xiě)操作詳解的相關(guān)資料,需要的朋友可以參考下
    2014-10-10
  • 如何通過(guò)Java代碼實(shí)現(xiàn)KMP算法

    如何通過(guò)Java代碼實(shí)現(xiàn)KMP算法

    這篇文章主要介紹了如何通過(guò)Java代碼實(shí)現(xiàn)KMP算法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • 解決springboot無(wú)法注入JpaRepository的問(wèn)題

    解決springboot無(wú)法注入JpaRepository的問(wèn)題

    這篇文章主要介紹了解決springboot無(wú)法注入JpaRepository的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-01-01

最新評(píng)論