SpringBoot整合JSP一站式解決方案


1.情景展示

  對於習慣於全棧式開發的我們,前端獲取后台的數據,jsp可以說是最好的選擇。

2.原因分析  

  但是,由於springboot推崇的是前后端分離,所以,springboot的內置tomcat沒有添加對jsp的支持。這樣,我們就不得不以json格式作為響應數據,這樣,我們在寫前端html的時候,就又不得不使用ajax來和后端進行數據交互,對於沒有進行前后端分離的開發人員來說,無疑是增加了獲取數據的開發時間成本。

  所以,springboot整合jsp是十分有必要的,因為jsp獲取數據相當簡單(前后端已經分離的,就不要考慮這種方式啦),下面講講如何整合jsp以及期間我所遇到的問題及解決辦法。  

3.解決方案

  以maven項目為例,最重要的一點就是:添加jsp依賴。

  第一步:添加對jsp的依賴

  需要引入兩個jar包:(不着急復制,這不一定符合你的要求)

<!-- 使用jsp引擎,springboot內置tomcat沒有此依賴 -->
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <version>9.0.36</version>
</dependency>
<!--增加對 JSP 文件的支持-->
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jsp-api</artifactId>
    <version>9.0.36</version>
</dependency>

  對於這兩個jar包的引用方式,不同的部署方式,引用方式是不同的。

  我們在網上看到的會多一個屬性標簽

   至於為什么加上這個標簽,他並沒有告訴你。這個原因我們必須不得不弄得明明白白,否則,你在引入之后會引發各種意想不到的問題。

  <scope></scope>標簽,用來聲明jar包的作用范圍,maven的生命周期包含編譯、測試、打包這三個階段,最終,在項目部署前,我們需要對項目進行打包,maven在執行打包命令時,會先對項目進行編譯和測試(其中,測試階段可以通過命令跳過),至於為什么要講這個,先挖個坑。

  provided,應用到maven的生命周期里就是:編譯和測試,換言之就是被它修飾的依賴,只有在編譯和測試階段,有效。更准確地來說,用來欺騙maven用的,因為如果編譯和測試階段沒有通過的話,maven是不會執行打包命令的。這樣做,雖然通過了編譯和測試階段,在最終打包時,該jar包是不會被打包到項目當中的(這一點,我已經印證過了,自己可以試一下,也可以看文末推薦的具體過程)(PS:在本示例中,沒有引入jsp項目相關jar包並不會造成maven打包失敗)。

  那么,回到上面的問題:為什么要加上這個標簽?因為他不想讓對應的jar包添加到項目當中。

  現在,我們來理一理思路:

  第一階段:使用springboot內置tomcat啟動項目

  第二階段:springboot內置tomcat不支持jsp

 

  spring-boot-starter-web包含spring-boot-starter-tomcat

  訪問一個jsp頁面的請求

  chrome瀏覽器下,會自動下載該請求的響應內容,並不會將其以html的形式展示到瀏覽器上(jsp會被tomcat解析成java格式的servlet) 

  到這里,可以小結一下:

  使用springboot內置tomcat啟動項目,要想使jsp生效,必須引入jsp依賴;

  第三階段:外置tomcat支持jsp 

  換句話說,就是:Apache官方的tomcat有jsp所需的jar包,這樣一來,當我們把項目部署到外置tomcat上時,項目引入的jsp jar包和tomcat的jsp jar包就會沖突。

  可以總結為:

  使用Apache官方tomcat啟動項目,就不需要引入這兩個jar包,引入反而是畫蛇添足。

  這樣一來:如果引入jar包不設置作用范圍,使用內置tomcat啟動項目可以正常訪問到jsp頁面,但是,部署到外置tomcat上時,就會引發jsp jar包沖突;

  如果設置作用范圍,內置tomcat啟動項目無法訪問到jsp頁面,而,部署到外置tomcat,我們則可以正常訪問項目。

  這就是顧此失彼的原因所在,絕大部分人也都是卡在了這里!!!

  對此,我一共總結了3種解決方案,供大家選擇:

  方案一:使用外置tomcat啟動項目。

  這一點,很好理解,因為,在沒有springboot前,我們都是將項目添加到tomcat中,然后啟動;

  所以,我們只需要將springboot的內置tomcat踢掉即可,不用添加對jsp的依賴。

  使用這種方式進行開發,需要我們將springboot項目當成普通的web項目,在idea里為該項目添加tomcat,部署,啟動。

  方案二:注釋。

  在開發環境下,使用springboot啟動項目,引入jsp依賴

  在生產環境下(也就是部署時), 刪除這兩個jar包的引用或者聲明為編譯和測試階段有效。

  同時,還需要剔除內置tomcat的依賴。

  方案三:開發環境和生產環境分離。

  通過maven的profile來實現

<profiles>
    <!--開發環境-->
    <profile>
        <id>dev</id>
        <!-- 是否激活本環境 -->
        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>
        <properties>
            <!--打包方式-->
            <project.packaging>jar</project.packaging>
            <!--打包時,需要進行測試-->
            <skipTests>false</skipTests>
        </properties>
        <dependencies>
            <!--jsp不能夠在jar中使用,只能夠在War中使用
            所以,如果確定部署項目的時候以jar的形式運行的話,則項目就不能使用jsp了,
            因為,maven在執行打包命令時,jsp是不會被打包到jar包當中的-->
            <!-- 使用jsp引擎,springboot內置tomcat沒有此依賴 -->
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-jasper</artifactId>
                <version>9.0.36</version>
            </dependency>
            <!--增加對 JSP 文件的支持-->
            <dependency>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-jsp-api</artifactId>
                <version>9.0.36</version>
            </dependency>
            <!-- 添加jstl標簽庫依賴模塊 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
            </dependency>
        </dependencies>
    </profile>
    <!--生產環境-->
    <profile>
        <id>prod</id>
        <!-- 默認激活本環境 -->
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <!--如果不指定成war,默認打的將是jar包-->
            <project.packaging>war</project.packaging>
            <!--打包時,跳過測試階段(因為測試階段會去連接數據庫,正式數據庫本地無法訪問,會導致打包失敗)-->
            <skipTests>true</skipTests>
        </properties>
        <!--項目中,編譯和測試階段用到的jar包,但tomcat中存在這些jar包,此時,在部署到tomcat中時,我們就需要把它們踢掉-->
        <dependencies>
            <!--內置tomcat(剔除該jar包)-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <!--只有編譯和測試階段生效-->
                <scope>provided</scope>
            </dependency>
            <!-- servlet依賴(只在開發時使用,因為部署到tomcat上時,tomcat有對應的jar包) -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <scope>provided</scope>
            </dependency>
            <!-- 添加jstl標簽庫依賴模塊 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
    </profile>
</profiles>  

  profiles標簽需要放在dependencies標簽上面 

  開發環境,勾選dev;生產環境,勾選prod,然后再導包,clean,package。 

  我使用的是方案三。  

  另外,要想使用jsp,就必須將項目打包成war形式,因為,maven在執行打包命令時,jsp是不會被打包到jar包當中的。所以,如果確定部署項目的時候以jar的形式運行的話,則項目就不能使用jsp了。

  需要注意的是:tomcat的jsp模板引擎與高版本oracle不兼容(解決方案仔細看)

<!-- oracle -->
<!--高版本的oracle jar包與jsp引擎 jar包沖突,啟動會報錯:找不到
ORACLE相關jar包:oraclepki.jar、osdt_core.jar、osdt_cert.jar、
ORAI18N相關jar包:orai18n-mapping.jar、orai18n-utility.jar、orai18n-collation.jar、orai18n-translation.jar、orai18n-net.jar、orai18n-servlet.jar、orai18n-lcsd.jar、orai18n-tools.jar、gdk_custom.jar
tomcat-embed-jasper相關jar包:xercesImpl.jar、xml-apis.jar、serializer.jar
等之類的jar包,但並不影響項目的正常運行-->
<dependency>
    <groupId>com.oracle.ojdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>19.3.0.0</version>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>com.oracle.ojdbc</groupId>
    <artifactId>orai18n</artifactId>
    <version>19.3.0.0</version>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>
<!--解決方案有三種:
1.不用理會:雖然啟動報錯,但並不影響項目的正常運行
2.切換成低版本的ORACLE驅動:比如OJDBC6
3.去掉對jsp模板引擎的引用:tomcat-embed-jasper,但是這樣,項目將無法使用jsp文件
PS:由於生產環境下,如果項目最終是要部署到tomcat上時,我們需要去除對於jsp模板引擎jar包的引用,部署到tomcat上,以上的jar包缺失的報錯信息並不存在,
所以,最佳的方案是第一種-->
<!--<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>ojdbc6</artifactId>
    <version>11.2.0.4</version>
</dependency>-->
<!-- json -->

  出現了類似xalan相關jar包找不到的錯誤,也不用管。

  到這里,本文的重點也就講完啦,基本上使用jsp就沒有問題啦。下面進行controller與jsp進行交互講解。

  配置視圖轉發jsp所在路徑

  這一步可有可無,看個人喜好。

  修改配置文件application.properties或者application.yml

####spring配置####
spring:
 ###控制器
  mvc:
    ##視圖
    view:
      #響應路徑前綴
      prefix: /jsp/
      #響應路徑后綴
      suffix: .jsp

  根據你的jsp實際所在位置設置路徑(如果jsp放置在webapp目錄下,則訪問路徑不用添加該目錄) 

  創建JSP控制器    

  根據自己的實際需要創建controller的目錄即可,這里僅供參考 

  配置歡迎頁和404頁面

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * 項目歡迎頁和404頁配置
 * @author: Marydon
 * @date: 2020年07月10日 0010 12:03
 */
@Controller
public class JspController {
    // 引用日志
    private static Logger logger = LoggerFactory.getLogger(JspController.class);

    /**
     * 首頁
     * @date: 2020年07月10日 0010 17:13
     * @param: 
     * @return: java.lang.String
     */
    // 這3個請求都會進入這個方法(這兩種注解方式都可以)
    // @RequestMapping(value = {"/","/index","/index.do"}, method = RequestMethod.GET)
    @GetMapping({"/","/index","/index.do"})
    public String index() {
        // 跳轉到歡迎頁
        return "index";
    }

    /**
     * 不存在的請求,跳轉到404頁面
     * @description: ErrorConfig已經攔截了404請求,然后映射到這個請求上
     * @date: 2020年07月10日 0010 17:10
     * @param: 
     * @return: java.lang.String
     */
    @GetMapping("/404.do")
    public String notFound() {
        // 跳轉到404頁
        return "404";
    }

} 
   請求轉發至jsp頁面並攜帶響應數據的三種方式
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

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

/**
 * 請求轉發至頁面(攜帶響應數據)的三種方式
 * 其中,第一種和第三種本質上一致
 * @author: Marydon
 * @date: 2020年07月10日 0010 12:03
 */
// 請求前綴
@RequestMapping("/demo")
// 返回頁面需要用這個注解
@Controller
public class demoDataController {
    // 引用日志
    private static Logger logger = LoggerFactory.getLogger(demoDataController.class);

    /*
     * 方式一:跳轉頁面並響應Map數據
     * @date: 2020年07月10日 0010 18:16
     * @param: map
     * @return: java.lang.String
     */
    @RequestMapping("/getMap.do")
    public String responseMap(Map<String, Object> map){
        map.put("time", new Date());
        map.put("message", "Map取值");
        //return 的是文件的路徑+名字
        // /jsp/demo/map.jsp
        return "demo/map";
    }

    /**
     * 方式二:返回ModelAndView
     * @date: 2020年07月10日 0010 18:23
     * @param: 
     * @return: org.springframework.web.servlet.ModelAndView
     */
    @RequestMapping("/getModelAndView.do")
    public ModelAndView responseModelAndView(){
        // 頁面位置 /jsp/demo/modelAndView.jsp
        ModelAndView mav = new ModelAndView("demo/modelAndView");
        mav.addObject("time", new Date());
        mav.addObject("message", "ModelAndView取值");
        return mav;
    }

    /*
     * 方法三:直接使用Model封裝內容,並返回頁面字符串
     * @date: 2020年07月10日 0010 18:38
     * @param: model
     * @return: java.lang.String
     */
    @RequestMapping("/getModel.do")
    public String responseModel(Model model){
        // 頁面位置 /jsp/demo/model.jsp
        model.addAttribute("time", new Date());
        model.addAttribute("message", "model");
        return "demo/model";
    }

    /*
     * 返回json數據
     * @decription:springmvc返回Json的兩種方式
     *  方式一:類添加注解@Controller,方法上添加@ResponseBody
     *  方式二:類上只需添加@RestController,方法上不用添加@
     *  使用這種方式,對應的類就只能返回json數據,而不能轉發至頁面上了(前后端分離一般采用的就是這種方式)
     * @date: 2020年07月17日 0017 17:14
     * @param: 
     * @return: java.util.Map<java.lang.String,java.lang.Object>
     */
    @ResponseBody
    @RequestMapping("/getJson.do")
    public Map<String, Object> responseJSON(){
        Map<String, Object> map = new HashMap<>();
        map.put("data","Json數據");
        return map;
    }
}

  介紹已經夠詳細的了,看注釋就能懂。

  配置響應頁面並取值

<%@ page language="java" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>數據交互一</title>
</head>

<body>
<h1>${message}:${time}</h1>
</body>
</html>

  map.jsp、model.jsp、modelAndView.jsp這三個頁面的取值方式用的都是EL表達式。

 

寫在最后

  哪位大佬如若發現文章存在紕漏之處或需要補充更多內容,歡迎留言!!!

 相關推薦:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM