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