jfinal 4.9整合spring-mvc-4.1.6

2.10.1.概述

整合思路

在jfinal中添加DispatcherServlet,DispatcherServlet加载spring的配置文件

2.10.2.整合spring-mvc

创建工程jfinal-4.9-spring-mvc-4.1.6

pom.xml

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <jdk.version>1.8</jdk.version>
</properties>
<dependencies>
  <dependency>
    <groupId>com.jfinal</groupId>
    <artifactId>jfinal-undertow</artifactId>
    <version>2.1</version>
  </dependency>
  
  <dependency>
    <groupId>com.jfinal</groupId>
    <artifactId>jfinal</artifactId>
    <version>4.9.01</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.1.6.RELEASE</version>
  </dependency>
</dependencies>
<build>
  <plugins>
    <plugin>
      <!-- java编译插件 -->
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.2</version>
      <configuration>
        <source>${jdk.version}</source>
        <target>${jdk.version}</target>
        <encoding>UTF-8</encoding>
      </configuration>
    </plugin>
  </plugins>
</build>


spring-mvc.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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
  xmlns:util="http://www.springframework.org/schema/util" 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/util
  http://www.springframework.org/schema/util/spring-util.xsd
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context.xsd
  http://www.springframework.org/schema/mvc
  http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  <!-- 默认的注解映射的支持 -->
  <mvc:annotation-driven />
  <!-- 开启controller注解支持 -->
  <context:component-scan base-package="com.alit.jfinal.springmvc.controller" />
</beans>


启动类AppConfig.java

package com.alit.jfinal.springmvc;
import com.jfinal.config.Constants;
import com.jfinal.config.Handlers;
import com.jfinal.config.Interceptors;
import com.jfinal.config.JFinalConfig;
import com.jfinal.config.Plugins;
import com.jfinal.config.Routes;
import com.jfinal.server.undertow.UndertowServer;
import com.jfinal.template.Engine;
public class AppConfig extends JFinalConfig {
  public static void main(String[] args) {
    UndertowServer.create(AppConfig.class).configWeb(builder -> {
      // 配置 Servlet
      String servletName = "dispathcer";
      builder.addServlet(servletName, "org.springframework.web.servlet.DispatcherServlet");
      builder.addServletMapping(servletName, "*.do");
      builder.addServletInitParam(servletName, "contextConfigLocation", "classpath:spring-mvc.xml");
      builder.setServletLoadOnStartup(servletName, 0);
    }).start();
  }
  public void configConstant(Constants me) { me.setDevMode(true);}
  public void configRoute(Routes me) { }
  public void configEngine(Engine me) { }
  public void configPlugin(Plugins me) { }
  public void configInterceptor(Interceptors me) { }
  public void configHandler(Handlers me) { }
}


HelloController.java

package com.alit.jfinal.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("Hello")
public class HelloController {
  @RequestMapping()
  @ResponseBody
  public String index() {
    return "Hello,World";
  }
}


启动之后访问成功

http://localhost/Hello.do

image.png


2.10.3.实现完美整合

[背景]

如果设置dispatcher的拦截路径为/ 则会测试失败

builder.addServletMapping(servletName, "/");

image.png

原因肯定是jfinal拦截了/


分析源码

UndertowServer.configJFinalFilter() 配置如下

image.png

JFinalFiler 的doFiler方法

isHander声明为false,但是经过 handler.hanlder之后就变成了true

image.png

通过debug调试进入发现进入到了ActionHandler

在ActionHandler中 getAction返回的所以执行了下图所示的上面的代码,返回了404

image.png

[解决思路1]

新增一个Handler,新增的SpringMVCHander默认会在ActionHanlder之前执行,根据url获取action,如果action为null,直接返回,此时isHandler第一个元素是false

[解决思路2]

修改ActionHanlder源码,将isHanlder[0]=true向下移动几行,如果action为null直接返回,不执行render方法

[解决思路3]

修改JFinalFiler,取消handler,直接使用spring mvc


我最终选择的是解决思路1但是ActionMapping从哪里来呢?发现JFinal有1个获取action的方法

JFinal.me().getAction(url, urlPara)


编写SpringMVCHandler 

package com.alit.jfinal.springmvc.handler;
package com.alit.jfinal.springmvc.handler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jfinal.core.Action;
import com.jfinal.core.JFinal;
import com.jfinal.handler.Handler;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SpringMVCHandler extends Handler {
  public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) {
    // 1.静态文件返回
    if (target.indexOf('.') != -1) {
      return;
    }
    String[] urlPara = { null };
    Action action = JFinal.me().getAction(target, urlPara);
    if (action == null) {
      String requestURI = request.getRequestURI();
      log.info("{} action is null ,return", requestURI);
      return;
    }
    // 让actionHanlder执行
    next.handle(target, request, response, isHandled);
  }
}

测试访问

添加到启动类

public void configHandler(Handlers me) {
  me.add(new SpringMVCHandler());
}

显示日志

image.png

处理成功

image.png


设置undertow.properties,修改controller文件后按Ctrl+S保存也会自动生效

image.png

undertow.properties

undertow.devMode=true

重新启动是0.2s 

访问1个不存在的路径

image.png


评论区

JFinal

2020-09-08 15:52

这种整合方式,不必修改 jfinal-undertow 项目,非常好

以前一些同学是改掉 jfinal-undertow 项目中的 JFinalFilter 换成 spring 的东东,显然不如这个方案好

李通

2020-09-08 17:15

@JFinal 主要是为了兼容旧项目,通过spring mvc整合eureka-server,否则我才不会去整合spring-mvc呢