Jbomo框架系列教程(二)-MVC 有更新!

  |   0 评论   |   2,432 浏览

第二章:MVC

​ MVC功能是fork至jfinal1.9版本,并在这基础上增强了某些功能,下面是简单的使用示例:

简单示例

  1. Controller类代码编写

继承com.jbomo.base.frame.core.Controller抽象类,任意写一个Action方法。

public class SimpleController extends Controller {
    public void simple(){
        renderText("helloWorld!---------");
    }
}
  1. Module配置类编写

实现Module模块接口,WebModule是接口Module的抽象类。配置SimpleController路由信息:

public class SimpleModule extends WebModule {
    @Override
    public void configRoute(Routes routes) {
        routes.add("/hello",SimpleController.class);
    }
    @Override
    public void configHandler(Handlers handlers) {
    }
    @Override
    public void configInterceptor(Interceptors interceptors) {
    }
}

> 所有有关当前模块的配置都在Module的实现类中进行配置,包括路由配置、持久化层映射、拦截器、处理器、全局参数配置等等。

  1. Main应用启动入口
public class SimpleAppliaction {
    public static void main(String[] args) {
        Jbomo.run();
    }
}
  1. 启动应用

浏览器中访问路径:http://localhost:8033/hello/simple

helloWorld!---------
  1. 应用host及端口配置

可以使用自定义配置应用host跟端口,在resources中新建config.properties

jbomo.devMode = true
jbomo.server.port = 8086
jbomo.server.host = localhost
  1. jbomo-example02-mvc示例工程目录如下:

1547794958196

Module配置类

​ Module既是模块和插件的实现接口,主要用于配置模块或者插件的初始化、路由、orm映射、拦截器等

public interface Module {
    void configRoute(Routes me);
    void configInterceptor(Interceptors me);
    void configTable(Tables tables);
    void configConstant(Constants me);
    void configHandler(Handlers me);
    void afterStart();
}

​ 下面详细说明几类常用配置:

configRoute

​ 此方法用来配置访问路由,如下代码配置,将”/hello”映射到SimpleController这个控制器。通过以下的配置,http://localhost:8033/hello/simple将访问SimpleController.simple()方法,而http://localhost/hello/将缺省访问到SimpleController.index()方法。

    public void configRoute(Routes routes) {
        routes.add("/hello",SimpleController.class);
    }

​ Routes类主要有如下两个方法:

	public Routes add(String controllerKey, Class<? extends Controller> controllerClass, String viewPath);
	public Routes add(String controllerkey, Class<? extends Controller> controllerClass);

​ 第一个参数controllerKey是指访问某个Controller所需要的一个字符串,该字符串唯一对应一个Controller,controllerKey仅能定位到Controller。

​ 第二个参数controllerClass是该controllerKey所对应到的Controller。

​ 第三个参数viewPath是指该Controller返回的视图的相对路径(该参数具体细节将在Controller相关章节中给出)。当viewPath未指定时默认值为controllerKey。

​ 路由规则如下:

url组成 访问目标
controllerKey YourController.index()
controllerKey/method YourController.method()
controllerKey/method/v0-v1 YourController.method(),所带 url 参数值为:v0-v1
controllerKey/v0-v1 YourController.index(),所带 url 参数值为:v0-v1

​ 访问一个确切的Action(Action定义见3.2节)需要使用controllerKey与method来精确定位,当method省略时默认值为index。urlPara是为了能在url中携带参数值,urlPara可以在一次请求中同时携带多个值,默认使用减号“-”来分隔多个值(可通过constants.setUrlParaSeparator(String)设置分隔符),在Controller中可以通过getPara(intindex)分别取出这些值。controllerKey、method、urlPara这三部分必须使用正斜杠“/”分隔。

​ 注意,controllerKey自身也可以包含正斜杠“/”,如“/admin/article”。

​ 在以上路由规则之外还提供了 ActionKey 注解,可以打破原有规则, 以下是代码示例,上述jbomo-example-simple示例中添加simple2 Action方法:

public class SimpleController extends Controller {
    public void simple(){
        renderText("helloWorld!---------");
    }

    @ActionKey("/simple2")
    public void simple2(){
        renderText("helloWorld simple2!---------");
    }
}

​ 在使用了 @ActionKey(“/simple2”)注解以后,actionKey由原来的“/hello/simple2”变为了“/simple2”。该注解还可以让actionKey中使用减号或数字等字符,如“/simple2/123-456”。http://localhost:8086/simple2

configInterceptor

​ 此方法用来配置Interceptor,如下代码配置了名为 AuthInterceptor 的拦截器,在此处配置的拦截器将会对所有的请求进行拦截,除非使用@ClearInterceptor 在 Controller 中清除。

    @Override
    public void configInterceptor(Interceptors interceptors) {
        interceptors.add(new SimpleInterceptor());
    }

​ Interceptor 配置粒度分为Global、Controller、Action 三个层次,其中以上代码配置粒度为全局。Controller 与 Action 级 的 Interceptor 配置将在后续章节中详细介绍。

configTable

​ 此方法用来配置ORM映射,代码如下:

    public void configTable(Tables tables) {
        tables.add("example_hello", Hello.class,"sharding");
    }

​ tables.add主要有两个方法:

    public Tables add(String tableName, Class<? extends Model<?>> modelClass,String datasources)
    public Tables add(String tableName, Class<? extends Model<?>> modelClass)

​ 第一个参数为数据库表名称。

​ 第二个参数为实体类(继承Model实体)的class。

​ 第三个参数为数据源,没有指定数据源则默认使用系统主数据源(main)。

数据源名称为config.properties配置中的jbomo.datasource.${xxx}.url中的${xxx}字符串配置

configConstant

​ 此方法用来配置系统常量值,如下代码示例:

    public void configConstant(Constants me) {
        super.configConstant(me);
        me.setMainRenderFactory(new BeetlRenderFactory(new ClasspathResourceLoader()));
        me.setViewType(ViewType.OTHER);
    }

​ 该示例配置为beetl插件的常量配置,通过设置RenderFactory以及ViewType来支持beetl模板。

configHandler

​ 此方法用来配置Handler, 如下代码配置了名为XssHandler的处理器, Handler可以接管所有 web请求,并对应用拥有完的控制权,可以很方便地实现更高层的功能性扩展。

    public void configHandler(Handlers me) {
        me.add(new XssHandler(ConstCore.SLASH + ConstCore.ACTIONKEY_PREFIX_ADMIN));
    }

afterStart

​ 系统启动后的回调方法,可以作为插件初始化代码使用。

    @Override
    public void afterStart() {
        try {
            init();
        }catch (Exception e){
            log.error("init plugins visitcnt error",e);
        }

        if(PLUGIN_RUNNING_STATUS){
            log.info("Visitcnt plugin started!");
        }
    }

Controller

概述

​ Controller 作为 MVC 模式中的控制器。应用的控制器都需要继承该类。Controller是定义Action 方法的地点,是组织Action 的一种方式,一个 Controller可以包含多个 Action。Controller是线程安全的。

Action

​ Controller以及在其中定义的 public无参方法称为一个 Action。Action 是请求的最小单位。Action 方法必须在Controller 中声明,该方法必须是 public可见性且没有形参。

public class SimpleController extends Controller {

    @Before(SimpleInterceptor2.class)
    public void simple(){
        renderText("helloWorld!---------");
    }

    @ClearInterceptor(ClearLayer.ALL)
    @ActionKey("/simple2")
    public void simple2(){
        renderText("helloWorld simple2!---------");
    }
}

​ 以上代码中定义了两个 SimpleController.simple()、SimpleController.simple2()。在Controller中提供了 getPara系列方法 setAttr方法以及render系列方法供Action 使用。

getPara系列方法

​ Controller提供了getPara系列方法用来从请求中获取参数。getPara系列方法分为两种类型。

​ 第一种类型为第一个形参为String的getPara系列方法。该系列方法是对HttpServletRequest.getParameter(Stringname)的封装,这类方法都是转调了HttpServletRequest.getParameter(Stringname)。

​ 第二种类型为第一个形参为int或无形参的getPara系列方法。该系列方法是去获取urlPara中所带的参数值。getParaMap与getParaNames分别对应HttpServletRequest的getParameterMap与getParameterNames。

方法调用 返回值
getPara(”title”) 返回页面表单域名为“title”参数值
getParaToInt(”age”) 返回页面表单域名为“age”的参数值并转为 int 型
getPara(0) 返回 url 请求中的 urlPara 参数的第一个值,如http://localhost/controllerKey/method/v0-v1-v2 这个请求将返回”v0”
getParaToInt(1) 返回url请求中的urlPara参数的第二个值并转换成int 型,如http://localhost/controllerKey/method/2-5-9这个请求将返回5
getParaToInt(2) http://localhost/controllerKey/method/2-5-N8 这个请求将返回 -8。注意:约定字母 N与n 可以表示负号,这对 urlParaSeparator为 “-” 时非常有用。
getPara() 返回 url 请求中的 urlPara 参数的整体值,如http://localhost/controllerKey/method/v0-v1-v2 这个请求将返回”v0-v1-v2”

getParaWithXssDecode()

​ 框架默认使用XssHandler对xss攻击进行特殊字符过滤,默认把特殊字符转成全角字符。当有些特殊情况需要提交包含特殊字符的参数,可以使用getParaWithXssDecode()获取原字符串。

​ 特殊字符包含:

'"#%&():<>\

注意:某些第三方应用回调场景,比如支付宝支付回调验签提交的参数会包含特殊字符,需要使用该方法获取参数,否则会导致验签失败

getFile 文件上传

​ Controller 提供了 getFile 系列方法支持文件上传。

特别注意:如果客户端请求为 multipart request(form 表单使用了 enctype=“multipart/form-data”) ,那么必须先调用 getFile 系列方法才能使 getPara系列方法正常工作, 因为multipart request 需要通过 getFile系列方法解析请求体中的数据,包括参数。

setAttr 方法

​ setAttr(String, Object)转调了 HttpServletRequest.setAttribute(String, Object),该方法可以将各种数据传递给 View 并在 View中显示出来。

render系列方法

​ render 系列方法将渲染不同类型的视图并返回给客户端。支持的视图类型有:Beetl、Jsp、FreeMarker、Velocity、JSON、File、Text、Html。

​ 通常情况下使用 Controller.render(String)方法来渲染视图,使用 Controller.render(String)时的视图类型由configConstant(Constants constants) 配置中的constants. setViewType(ViewType)来决定,该设置方法支持的 ViewType有:FreeMarker、JSP、Velocity,Other。

​ 也可以使用 me.setMainRenderFactory(myFactory)来自定义Render工厂实现,上述configConstant示例代码beetl插件就是通过实现IMainRenderFactory来自定义Render。

由于undertow默认并不支持JSP模板引擎,如果需要使用JSP模板该应用不能使用内嵌容器直接启动,而是需要部署到外部容器,通常是tomcat上。实际项目能进行前后端完全分离的业务场景一致提倡使用前端来渲染数据,后端提供api数据接口。需要用到模板引擎时提倡引入beetl模板支持,使用beetl模板引擎。

        <dependency>
            <groupId>com.jbomo</groupId>
            <artifactId>jbomo-plugins-beetl</artifactId>
            <version>${jbomo.version}</version>
        </dependency>

这样做即可以节省编码过程中调试的时间成本,又可以统一应用的部署方式。

​ 假设在configRoute(Routes routes) 中有如下Controller映射配置 :

routes.add("/user", UserController.class, "/path"),

​ render(String view)使用例子:

方法调用 描述
render(”test.html”) 渲染名为 test.html 的视图,该视图的全路径为”/path/test.html”
render(”/other_path/test.html”) 渲染名为 test.html 的视图,该视图的全路为”/other_path/test.html”,即当参数以”/”开头时将采用绝对路径。

​ 其它render方法使用例子:

方法调用 描述
renderFreeMarker(”test.html”) 渲染名为 test.html 的视图,且视图类型为FreeMarker。
renderJsp(”test.html”) 渲染名为 test.html 的视图,且视图类型为 Jsp。
renderVelocity(“test.html”) 渲染名为test.html的视图,且视图类型为Velocity。
renderJson() 将所有通过 Controller.setAttr(String, Object)设置的变量转换成 json 数据并渲染。
renderJson(“users”, userList) 以”users”为根,仅将 userList 中的数据转换成 json数据并渲染。
renderJson(user) 将user对象转换成json 数据并渲染。
renderJson(“{\”age\”:18}” ) 直接渲染 json 字符串。
renderJson(newString[]{“user”, “blog”}) 仅将setAttr(“user”, user)与setAttr(“blog”, blog)设置的属性转换成json 并渲染。使用setAttr设置的其它属性并不转换为 json。
renderFile(“test.zip”); 渲染名为 test.zip 的文件,一般用于文件下载
renderText(“Hello !”) 渲染纯文本内容”Hello !”。
renderHtml(“Hello Html”) 渲染Html 内容”Hello Html”。
renderError (404 , “test.html”) 渲染名为 test.html 的文件,且状态为404。
renderError (500 , “test.html”) 渲染名为 test.html 的文件,且状态为 500。
renderNull() 不渲染,即不向客户端返回数据。
render(new XmlRender()) 使用自定义的 XmlRender来渲染。

除 renderError方法以外,在调用 render系列的方法后程序并不会立即返回,如果需要立即返回需要使用 return语句。在一个action 中多次调用 render方法只有最后一次有效。

Interceptor

概述

​ 拦截器通过实现 Interceptor 接口以及使用@Before annotation 或者全局拦截器进行配置。@Before annotation可以细粒度的配置在每个Action上,或者配置在Controller上。。Interceptor 并非线程安全的,线程安全拦截器需要继承PrototypeInterceptor 来实现。

Interceptor 应用

​ Interceptor 接口定了一个方法 void intercept(ActionInvocation ai)。 如下代码将在被拦截器的 Action 前输出一行文本到控制台:

public class SimpleInterceptor2 implements Interceptor {
    @Override
    public void intercept(ActionInvocation ai) {
        System.out.println("--------intercept---局部拦截器-------------");
        ai.invoke();
    }
}

​ 定义好拦截器后,可以很方便地在 action 调用前后插入切面代码来实现 AOP。

Interceptor 配置

​ 拦截器配置共分三个级别:Global级、Controller级、Action级。Global级的拦截器将对所有 Action 进行拦截,Controller 级拦截器将对该 Controller 中所有 Action 进行拦截,Action级拦截器仅对该 Action 进行拦截。

​ Global 级拦截器在上述的configInterceptor(Interceptors me)中进行配置(参考上述例子)。Controller级拦截器使用@Before annotation放置在Controller类定义前进行配置。 Action级拦截器使用@Before annotation 放置在Action 定义前进行配置。

​ 配置示例如下:

@Before(SimpleInterceptor3.class) // Controller级别拦截器
public class SimpleController extends Controller {

    @Before(SimpleInterceptor2.class) // Action级别拦截器
    public void simple(){
        renderText("helloWorld!---------");
    }

    @ClearInterceptor(ClearLayer.ALL) // 清除所有拦截器
    @ActionKey("/simple2")
    public void simple2(){
        renderText("helloWorld simple2!---------");
    }

    @ClearInterceptor // 清除上一级拦截器,也就是清除Controller的拦截器
    @ActionKey("/")
    public void simple3(){
        renderText("helloWorld simple3!---------");
    }
}

​ ClearInterceptor 默认仅清除上一级别的拦截器。Action 级的上一级为 Controller 级,Controller 级的上一级为Global 级。如果需删除多级拦截器,可以为ClearInterceptor 加入参数ClearLayer.ALL。


评论

发表评论

validate