# Magician文档
# Magician-Http
# 运行环境
JDK8+
# 引入依赖
<dependency>
<groupId>com.github.yuyenews</groupId>
<artifactId>Magician</artifactId>
<version>2.0.7</version>
</dependency>
<!-- 这是日志包,必须有,不然控制台看不到东西,支持任意可以和slf4j桥接的日志包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.12</version>
</dependency>
# 创建Handler(HTTP服务)
@HttpHandler(path="/demo")
public class DemoHandler implements HttpBaseHandler {
@Override
public void request(MagicianRequest request, MagicianResponse response) {
// response data
request.getResponse()
.sendJson("{'status':'ok'}");
}
}
# 接收参数
// 根据参数名称 获取一个参数
request.getParam("param name");
// 获取参数名称相同的多个参数
request.getParams("param name");
// 根据参数名称 获取文件
request.getFile("param name");
// 获取参数名称相同的多个文件
request.getFiles("param name");
// 获取本次请求传输的所有文件,key为 参数名称
request.getFileMap();
// 如果本次请求时json传参,可以用这个方法获取json字符串
request.getJsonParam();
// 根据名称 获取请求头
request.getRequestHeader("header name");
// 获取所有请求头
request.getRequestHeaders();
# 响应参数
// 响应文本数据
request.getResponse().sendText("");
// 响应html数据
request.getResponse().sendHtml("");
// 响应其他数据,这种方式需要 先设置响应头的Content-Type
request.getResponse().sendData("");
// 响应json数据
request.getResponse().sendJson("");
// 响应流数据,一般用作文件下载
request.getResponse().sendStream("");
// 响应错误数据,格式 {"code":500, "msg":""}
request.getResponse().sendErrorMsg(500, "");
# 创建WebSocketHandler(WebSocket服务)
@WebSocketHandler(path = "/websocket")
public class DemoSocketHandler implements WebSocketBaseHandler {
/**
* 当连接进来时,触发这个方法
*/
@Override
public void onOpen(WebSocketSession webSocketSession) {
// 给客户端发送消息
webSocketSession.sendString("send message");
}
/**
* 当连接断开时,触发这个方法
*/
@Override
public void onClose(WebSocketSession webSocketSession) {
}
/**
* 当客户端发来消息时,触发这个方法
* 第二个参数 message 就是客户端发送过来的消息
*/
@Override
public void onMessage(WebSocketSession webSocketSession, byte[] message) {
System.out.println("收到了:" + new String(message));
// 给客户端发送消息
webSocketSession.sendString("send message");
}
}
# 启动服务
无论是HTTP服务 还是WebSocket服务,都是这么启动
基础启动
Magician.createHttp()
.scan("com.test")// 扫描范围(包名)
.bind(8080); // 监听的端口
自定义配置启动
// 这段配置可以提取出去,不用跟下面的启动代码放在一起
MagicianConfig magicianConfig = new MagicianConfig();
magicianConfig.setNumberOfPorts(3); // 允许同时监听的端口数量,默认1个
magicianConfig.setBossThreads(1); // netty的boss线程数量 默认1个
magicianConfig.setWorkThreads(3); // netty的work线程数量 默认3个
magicianConfig.setNettyLogLevel(LogLevel.DEBUG); // netty的日志打印级别
magicianConfig.setMaxInitialLineLength(4096); // http解码器的构造参数1,默认4096 跟netty一样
magicianConfig.setMaxHeaderSize(8192); // http解码器的构造参数2,默认8192 跟netty一样
magicianConfig.setMaxChunkSize(8192); // http解码器的构造参数3,默认8192 跟netty一样
HttpServer httpServer = Magician.createHttp()
.scan("com.test")// 扫描范围(包名)
.setConfig(magicianConfig); // 添加配置
httpServer.bind(8080); // 监听端口
// 如果要监听多个端口
httpServer.bind(8081);
httpServer.bind(8082);
# Magician-Route
# 引入依赖
在Magician项目的基础上 添加这个依赖
<dependency>
<groupId>com.github.yuyenews</groupId>
<artifactId>Magician-Route</artifactId>
<version>1.0.0</version>
</dependency>
# 创建核心Handler
只允许有一个HttpHandler,这个Handler作为分发器,将请求分发给Route
@HttpHandler(path="/")
public class DemoHandler implements HttpBaseHandler {
@Override
public void request(MagicianRequest magicianRequest, MagicianResponse response) {
try{
// 主要是这句
MagicianRoute.request(magicianRequest);
} catch (Exception e){
}
}
}
# 修改扫描范围
- 扫描范围 需要包含【handler,route,拦截器 所在的包名】
- 多个可以逗号分割,也可以直接配置成 他们的父包名
Magician.createHttp()
.scan("扫描范围需要包含 handler,route,拦截器")
.bind(8080);
# 创建路由
- 这样的类可以创建多个,根据你的需求 将路由分开创建
- 每个路由内部,如果没有特别的需要 就不需要加try-catch,框架内部做了处理,一旦发生异常,会将异常信息以json的形式响应给客户端
- 直接返回需要响应的对象,框架会自动转成json并返回给客户端,你也可以采用如下示例中“Magician的原生响应方式” 将数据返回给客户端,具体可以看Magician文档的《响应参数》
@Route
public class DemoRoute implements MagicianInitRoute {
@Override
public void initRoute(MagicianRouteCreate routeCreate) {
routeCreate.get("/demo/getForm", request -> {
return "{\"msg\":\"hello login\"}";
});
// Magician的原生响应方式
routeCreate.get("/demo/getForm2", request -> {
request.getResponse().sendJson("{\"msg\":\"hello login\"}");
return null;
});
routeCreate.post("/demo/json", request -> {
DemoResponseVo demoResponseVo = new DemoResponseVo();
demoResponseVo.setName("Beerus");
return demoResponseVo;
});
}
}
# 传统方式接收参数
这里只是简单的列举一下,具体的可以看Magician文档里面的《接收参数》
// 获取 表单 以及 formData 提交的参数
request.getParam("参数name");
// formaData提交,获取文件
request.getFile("参数name");
// 获取请求头
request.getRequestHeader("请求头name");
// 获取json提交的参数
request.getJsonParam();
# 实体接收参数
public class ParamVO {
// ----- 字段名称 要跟 请求的参数name一致;如果是json传参,这个实体类只要跟json的结构保持一致即可-----
// 普通参数
private Integer id;
private String name;
private String[] ids
// 文件参数
private MixedFileUpload mixedFileUpload;
private MixedFileUpload[] mixedFileUploads;
// ----- 需要get, set,这里就不写了,节约点篇幅 -----
}
# 参数自动校验
在字段上 加上注解即可
// 不可为空,且大小在10-100之间
@Verification(notNull = true, max = "100", min = "10", msg = "id不可为空且大小必须在10-100之间")
private Integer id;
// 正则校验
@Verification(reg = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,12}$",msg = "密码不可以为空且必须是6-12位数字字母组合")
private String password;
# 属性解释
- notNull:是否为空,设置为true说明不可为空,对基本类型无效(不能赋值为null的类型都无效)
- max:最大值,只对int,double,float,BigDecimal等数字类型有效
- min:最小值,只对int,double,float,BigDecimal等数字类型有效
- msg:校验不通过的时候,返回前端的提示文字
- reg:正则表达式,只对String类型有效
# 将参数转化为实体对象
如果你想让实体类顺利的接收到参数,并且让参数验证生效,那么必须做如下步骤, 这种方式 底层是用的反射,如果你无法接受反射的性能,那么可以不用这种方式,选择权在你自己
- 只转化
routeCreate.get("/demo/getForm", request -> {
DemoVO demoVO = ConversionUtil.conversion(request, DemoVO.class);
return "{\"msg\":\"hello login\"}";
});
- 转化+参数验证
如果验证失败,conversionAndVerification 方法会抛出一个异常,这个异常会自动被响应给客户端,不需要开发者处理
routeCreate.get("/demo/getForm", request -> {
DemoVO demoVO = ConversionUtil.conversionAndVerification(request, DemoVO.class);
return "{\"msg\":\"hello login\"}";
});
如果你想获取到验证失败的提示信息 自己处理,可以用这种方式
routeCreate.get("/demo/getForm", request -> {
try {
DemoVO demoVO = ConversionUtil.conversionAndVerification(request, DemoVO.class);
} catch(VerificationException e){
// 这个就是 验证失败的提示信息
String msg = e.getMessage();
}
return "{\"msg\":\"hello login\"}";
});
# 创建拦截器
跟路由一样,这种类也可以创建多个,根据你的需求 分开创建拦截器
- 第一个参数为拦截规则,全部拦截 配置 * 即可,否则的话,必须以 / 开头
- 如果拦截器顺利放行的话,返回SUCCESS就好了,如果不给通过,那么直接返回 错误提示信息(返回对象会自定转成json)
@Interceptor
public class DemoInter implements MagicianInitInterceptor {
@Override
public void initInterceptor(MagicianInterceptorCreate interceptorCreate) {
interceptorCreate.addInterceptor("/demo/*", new MagicianInterceptor() {
@Override
public Object before(MagicianRequest magicianRequest) {
System.out.println("进入了拦截器");
return SUCCESS;
}
@Override
public Object after(MagicianRequest magicianRequest, Object o) {
return SUCCESS;
}
});
interceptorCreate.addInterceptor("/*/form", new MagicianInterceptor() {
@Override
public Object before(MagicianRequest magicianRequest) {
System.out.println("进入了拦截器2");
return SUCCESS;
}
@Override
public Object after(MagicianRequest magicianRequest, Object o) {
return SUCCESS;
}
});
}
}
# JWT管理
创建一个jwt管理对象, 每次builder都是一个新的对象,所以务必写一个静态的工具类来管理
JwtManager jwtManager = JwtManager
.builder()
.setSecret("秘钥")
.setCalendarField(Calendar.MILLISECOND) // 过期时间单位,默认:毫秒
.setCalendarInterval(86400);// 过期时间,默认86400
创建token
String token = jwtManager.createToken(要存入的对象);
还原token
原对象类 原对象 = jwtManager.getObject("token字符串", 原对象类.class);
# Magician-Containers
# 引入依赖
<dependency>
<groupId>com.github.yuyenews</groupId>
<artifactId>Magician-Containers</artifactId>
<version>1.0.1</version>
</dependency>
# 标记Bean
在类上面加一个注解即可,不可以用在 controller 上,也不是所有的类都需要变成一个 bean,开发者可以随意决定。
我们推荐:在你需要在这个类里面使用 AOP 或者定时任务的时候,才把它变成一个 bean。
@MagicianBean
public class DemoBean {
}
# AOP
编写AOP的逻辑
public class DemoAop implements BaseAop {
/**
* 方法执行前
* @param args 被执行的方法的参数
*/
public void startMethod(Object[] args) {
}
/**
* 方法执行后
* @param args 被执行的方法的参数
* @param result 被执行的方法的返回数据
*/
public void endMethod(Object[] args, Object result) {
}
/**
* 方法执行出现异常
* @param e 被执行的方法的异常信息
*/
public void exp(Throwable e) {
}
}
将逻辑挂到要监听的方法上
@MagicianBean
public class DemoBean {
@MagicianAop(className = DemoAop.class)
public void demoAopMethod() {
}
}
# 定时任务
@MagicianBean
public class DemoBean {
// loop 是轮训间隔,单位: 毫秒
@MagicianTimer(loop=1000)
public void demoTimerMethod() {
}
}
# 初始化Bean
@MagicianBean
public class DemoBean implements InitBean {
public void init(){
// 这个方法会在 所有Bean都创建好了以后自动执行
// 可以将需要初始化的数据 和 逻辑 写在这里
}
}
# 获取Bean对象
@MagicianBean
public class DemoBeanTwo {
private DemoBean demoBean = BeanUtil.get(DemoBean.class);
}
# Magician-Configure
# 引入依赖
<dependency>
<groupId>com.github.yuyenews</groupId>
<artifactId>Magician-Configure</artifactId>
<version>1.0.0</version>
</dependency>
# 加载配置文件
目前只支持 properties文件,你可以在任意目录下创建,然后使用以下方式将文件加载到项目中
从本机任意目录加载
// 必须写文件的绝对路径
MagicianConfigure.load("/home/xxx/application.properties", ReadMode.EXTERNAL);
从当前项目的资源目录下加载
// 类资源下的文件的路径
MagicianConfigure.load("/application.properties", ReadMode.LOCAL);
从远程目录加载
// 远程文件路径, 只支持http协议
MagicianConfigure.load("https://www.test.com/application.properties", ReadMode.REMOTE);
# 获取配置数据
// 如果配置文件里有userName这个key,那么就会直接使用,如果没有 那么会去环境变量读取
String userName = Environment.get("userName");