Redkale 入门教程 02

Stella981
• 阅读 663

        REST是 Redkale 的主要功能之一,REST提供的功能是根据Service自动生成HttpServlet,需要注意的是 Redkale里的REST与标准的RESTfull规范完全不同,仅仅名称类似。标准的REST规范比较死板,只是在请求URL和Method上做文章,功能单一。Redkale里的REST功能是很强大的, 无论登陆、鉴权、文件上传下载、WebSocket都可以REST化,几乎完全可以省去HttpServlet。

注解类名

功能描述

@RestService

标记Service需要REST化。

@RestMapping

标记请求的方法名,同一方法上可重复标记(需确保name值在Service中是唯一的)。
其标记的Service方法只能throws IOException或不抛异常

@RestConvert

标记请求的方法名上,对返回值以JSON形式输出时进行字段的屏蔽或开启进行设置。

@RestParam

获取常规参数值, 字段类型可以是 基础数据类型/Flipper/CompletionHandler/String/JavaBean
name='&'    表示当前用户(@HttpUserType)
name='#'    表示截取uri最后一段
name='#xxx:'    表示从uri中/pipes/xxx:v/截取xxx:的值

@RestHeader

通过request.getHeader获取参数值, 字段类型只能是String

@RestCookie

通过request.getCookie获取Cookie值, 字段类型只能是String

@RestBody

通过request.getBody获取参数值, 字段类型只能是String/byte[]/JavaBean

@RestSessionid

获取sessionid, 字段类型只能是String

@RestAddress

获取客户端IP地址, 字段类型只能是String

@RestURI

获取请求URL, 字段类型只能是String

@RestUploadFile

获取上传文件, 字段类型只能是File/File[]/byte[]

WebSocket

@RestWebSocket

标记WebSocket需要REST化,只能标记在WebSocket的子类上

@RestOnMessage

WebSocket的消息路由,类似@RestMapping,不同的请求映射到不同的方法

        标记@RestService的Service对象在服务启动时会自动生成原始的HttpServlet加载到当前的HttpServer中,其HttpServlet的请求URL规则为:path + "/" + @RestService.catalog() + "/" + @RestService.name() + "/*", 其中path为application.xml文件中节点的path属性值。节点rest和servlets设计一个path属性是为了所有动态请求加个前缀方便静动分离,没有采取.jsp .do那种刷存在感的后缀方式也是处于安全考虑,外界根据URL无法判断后台使用的是什么语言或框架开发。
        REST会根据Service方法的返回类型不同做出不同的结果输出。

返回类型

功能描述

void

以RetResult.success()的JSON形式输出。

String

以字符串输出。

File

以下载文件形式输出。

HttpResult

将HttpHeader、HttpCookie、Result统一输出

CompletableFuture

异步输出,根据CompletableFuture.get()结果类型进行不同形式输出

JavaBean/其他

以JSON形式输出

        要开启REST功能需要在application.xml对应的HttpServer下加入rest节点:

Redkale 入门教程 02

        如果需要加入鉴权功能更,需要自定义HttpServlet基类,并重载preExecute、authenticate方法。详情见 BaseHttpServlet

用户登陆范例

@RestService(name = "user", comment = "用户服务") public class UserService extends AbstractService {

@RestMapping(name = "login", auth = false, comment = "用户登陆")
public RetResult login(String account, String password, @RestHeader(name = "User-Agent") String agent,
    @RestSessionid(create = true) String sessionid, @RestAddress String clientAddr) {
    if (!"redkale".equals(account)) {
        return new RetResult(1001, "账号不是redkale");
    }
    if (!"123456".equals(password)) {
        return new RetResult(1002, "密码错误");
    }
    System.out.println("用户(" + account + ")的回话ID为: " + sessionid + ", 通过客户端(" + agent + ")在" + clientAddr + "登陆。");
    return RetResult.success();
}

}

        浏览器输入: http://127.0.0.1:6060/pipes/user/login?account=redkale&password=123456 
        返回结果: {"retcode":0,"success":true} 
        后台打印: 用户(redkale)的回话ID为: 6110627db03b2b4a2c45a2fcb2aa1403, 通过客户端(Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36)在127.0.0.1登陆。

        REST的注解不仅可以注解在Service的方法参数上, 还可以在Service的方法的JavaBean参数的类里的字段进行注解。

public class LoginBean {

private String account;

private String password;

@RestHeader(name = "User-Agent")
private String agent;

@RestSessionid(create = true)
private String sessionid;

@RestAddress
private String clientAddr;

@Override
public String toString() {
    return JsonConvert.root().convertTo(this);
}

/\*\* 以下省略getter setter方法 \*/

}

@RestService(name = "user", comment = "用户服务") public class UserService extends AbstractService {

@RestMapping(name = "login", auth = false, comment = "用户登陆")
public RetResult login(LoginBean bean) {
    if (bean == null) {
        return new RetResult(1000, "没有登陆信息");
    }
    if (!"redkale".equals(bean.getAccount())) {
        return new RetResult(1001, "账号不是redkale");
    }
    if (!"123456".equals(bean.getPassword())) {
        return new RetResult(1002, "密码错误");
    }
    System.out.println("用户(" + bean.getAccount() + ")通过客户端(" + bean.getAgent() + ")在" + bean.getClientAddr() + "登陆。");
    return RetResult.success();
}

}

        浏览器输入: http://127.0.0.1:6160/pipes/user/login?bean={account:redkale,password:123456} 
        返回结果: {"retcode":0,"success":true} 
        后台打印: 用户(redkale)通过客户端(Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36)在127.0.0.1登陆。

        如果用户登陆成功后需要跳转到首页或者还可能需要输出一些Cookie值,就需要使用HttpResult作为返回结果,例如:

@RestService(name = "user", comment = "用户服务") public class UserService extends AbstractService {

@RestMapping(name = "login", auth = false, comment = "用户登陆")
public HttpResult login(LoginBean bean) {
    if (bean == null) {
        return new HttpResult<>(new RetResult(1000, "没有登陆信息"));
    }
    if (!"redkale".equals(bean.getAccount())) {
        return new HttpResult<>(new RetResult(1001, "账号不是redkale"));
    }
    if (!"123456".equals(bean.getPassword())) {
        return new HttpResult<>(new RetResult(1002, "密码错误"));
    }
    System.out.println("用户(" + bean.getAccount() + ")通过客户端(" + bean.getAgent() + ")在" + bean.getClientAddr() + "登陆。");
    return new HttpResult().header("Location", "/index.html").cookie(new HttpCookie("curraccount", bean.getAccount()));
}

}

文件上传

@RestService(name = "file", comment = "文件服务") public class FileService extends AbstractService {

private static final Logger logger = Logger.getLogger(FileService.class.getSimpleName());

private static final String format = "%1$tY%1$tm%1$td%1$tH%1$tM%1$tS";

@RestMapping(name = "upload", auth = false, comment = "文件上传,不鉴权")
public RetResult upload(@RestUploadFile(maxLength = 1 \* 1024 \* 1024, fileNameReg = ".\*\\\\.doc$") File tmpFile) throws IOException {
    if (tmpFile == null) return new RetResult(1001, "没有上传文件或文件大小超过1M或文件不是.doc后缀");
    //按日期命名 如 file-20170601133520.doc
    try {
        logger.finest("用户上传的文件名为: " + MultiContext.getFileName(tmpFile));
        File destFile = new File("D:/docs/file-" + String.format(format, System.currentTimeMillis()) + ".doc");
        destFile.getParentFile().mkdirs();
        if (!tmpFile.renameTo(destFile)) { //tmpFile与destFile不在同一盘符下会导致renameTo失败
            java.nio.file.Files.copy(tmpFile.toPath(), destFile.toPath(), StandardCopyOption.ATOMIC\_MOVE);
        }
    } finally { //如果发生异常,将临时文件从{APP\_HOME}/tmp 目录下删除
        tmpFile.delete();
    }
    return RetResult.success();
}

}

        WebSocket与其REST化将在以后的章节详细介绍。

        转载请注明出处:https://redkale.org/course02_rest.html

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
3年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Redkale 技术详解 01
Redkale技术详解01双亲委托模型Redkale(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fredkale.org%2Findex.html)里大量使用了双亲委托模型,序列化的ConvertFactory、依赖注入的ResourceFactory、服务
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这