本架构基于Java EE 7.0封装了一套类restful风格的HTTP协议网络数据处理API
该API中,文件上传基于Servlet 3.1
其设计目的只在于提供简单易于使用的HTTP服务端程序
HTTP数据处理API完全基于Servlet,所以使用之前必须在网站的 web.xml中配置如下
<servlet>
<servlet-name>CentralController</servlet-name>
<servlet-class>org.jtry.framework.net.http.CentralController</servlet-class>
<init-param>
<param-name>controllerConfigClass</param-name>
<param-value>com.test.init.WebConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CentralController</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
其中servlet节点配置
servlet-class 使用org.jtry.framework.net.http.CentralController
url-pattern 指定前端数据处理程序的URL根路径
再设置该servlet在服务发布时的初始化顺序
最后配置初始化参数(init-param) ,参数名(param-name)使用controllerConfigClass,值(param-value)使用编写好的配置类包路径
配置类由使用者自己定义,但必须实现org.jtry.framework.net.http.entity.ControllerConfig接口也可以继承org.jtry.framework.net.http.entity.DefaultControllerConfig类
再根据实际需要,实现或重写如下方法
String getCharacterEncoding();
String getPrefix();
String getSuffix();
String[] getControllersPackages();
Class<? extends ControllerDataChecker> getDataCheckerClass();
Class<? extends TypeProcessor<?>>[] getTypeProcessorClasss();
getCharacterEncoding 返回要设定的网络传输数据字符集
getPrefix 返回全局网络URL前缀
getSuffix 返回全局网络URL后缀
getControllersPackages 返回前端数据处理程序所在包路径数组
getDataCheckerClass 返回全局网络数据检查器的Class
getTypeProcessorClasss 返回类型处理器的Class组
实际使用例子如下
public class WebConfig extends DefaultControllerConfig
{
@Override
public String getCharacterEncoding() {
return "GBK";
}
@Override
public String getPrefix() {
return "/admin/html/";
}
@Override
public String getSuffix() {
return ".html";
}
@Override
public String[] getControllersPackages() {
return new String[] { "com.test.controller", "com.test.web.controller" };
}
@Override
public Class<? extends ControllerDataChecker> getDataCheckerClass() {
return MyControllerDataChecker.class;
}
@SuppressWarnings("unchecked")
@Override
public Class<? extends TypeProcessor<?>>[] getTypeProcessorClasss() {
Class<?>[] typeProcessorClasss = new Class<?>[]{
XmlTypeProcessor.class,
JsonTypeProcessor.class,
UserTypeProcessor.class
};
return (Class<? extends TypeProcessor<?>>[]) typeProcessorClasss;
}
}
web.xml配置完毕之后,在前端数据处理程序使用@Path注解如下指定就可以接收HTTP请求
@Path("user")
public class Passport {
UserService userService;
@Path("login")
public String login(User
user) throws SQLException {
if (userService.login(user.getName())) {
return "index";
} else {
return "login";
}
}
例子中login方法的请求的URL为http://IP:端口/网站根路径/user/login
如果要为参数User赋值请直接使用HTTP协议定义的查询字符串键值对的形式
比如User类的属性如下
public class User {
private String name;
private Integer age;
private Double money;
private String phone;
private String regTime;
那么请求URL可以写为
http://IP:端口/网站根路径/user/login?name=text&age=26
这样参数User的name属性与age属性都会被赋值
如果login的参数为基本类型则需要在参数上加上@Mark注解标注查询字符串的键
@Path("login")
public String login(@Mark("name")String name) throws SQLException {
if (userService.login(name)) {
return "index";
} else {
return "login";
}
}
如果传入login的是一个Json则需要在参数上加上@Mark注解并指定isJson 为 true这时value标注的将是一个json路径
比如传入的json格式为{"user":{"name":"test","age":18}},那么可以如下指定
@Path("login")
public String login(@Mark(isJson = true, value = "user.age") int age) throws SQLException {
if (age > 18) {
return "index";
} else {
return "login";
}
}
也可以这样指定
@Path("login")
public String login(@Mark(isJson = true, value = "user") User user) throws SQLException {
if (userService.login(user.getName())) {
return "index";
} else {
return "login";
}
}
如果传入的json是一个数组{"users":[{"name":"test","age":18},{"name":"test2","age":20}]},那么可以指定具体下标对象
@Path("login")
public String login(@Mark(isJson = true, value = "users.0") User user) throws SQLException {
if (userService.login(user.getName())) {
return "index";
} else {
return "login";
}
}
也可以这样指定具体下标的对象具体属性
@Path("login")
public String login(@Mark(isJson = true, value = "users.0.age") int age) throws SQLException {
if (age > 18) {
return "index";
} else {
return "login";
}
}
总之只要知晓传入的json格式并使用正确的json路径,那么就可以直接取到任何深度任何类型的值
不同的前端数据处理程序类可以标注同一个@Path值,如下所示
@Path("user")
public class Passport {
@Path("user")
public class AdminController {
但必须这两个类方法中的@Path值不能存在重复
因为得保证类的@Path值与方法上的@Path值组合起来在全局是唯一的,如果有重复那么只能访问其中的一个
此外还可以在类或方法上使用@Path标注访问类型
@Path(value = "user", type = RequestMethod.POST)
public class Passport {
@Path(value = "login",type = RequestMethod.GET)
public String login(@Mark("name") String name) throws SQLException {
if (userService.login(name)) {
return "index";
} else {
return "login";
}
}
如上标注之后该类的全部方法都只允许POST方式访问,但login方法可以使用GET方式访问
前端数据处理程序类与方法可以不使用@Path注解,那么将会使用类名与方法名的全小写字符替代
public class Passport {
UserService userService;
public String login(User user) throws SQLException {
if (userService.login(user.getName())) {
return "index";
} else {
return "login";
}
}
上面例子的访问URL为
http://IP:端口/网站根路径/passport/login
如果前端数据处理程序类包含一个名称为index的方法
那么直接使用
http://IP:端口/网站根路径/passport
就可以访问到该方法
public class Passport {
UserService userService;
public String index() {
return "/login.html";
}
如果要获取到HttpServletRequest、HttpServletResponse、HttpSession这些Servlet对象,请直接在参数中定义
@Path("login")
public String login(HttpServletRequest request,HttpServletResponse response,HttpSession session,User user) throws SQLException {
if (userService.login(user.getName())) {
return "index";
} else {
return "login";
}
}
当进入到该方法的时候,这些参数将会被赋值
前端数据处理程序类中接收前段请求的方法的返回值类型应该被定义为String
因为其返回的是一个页面的URL或者另一个前端数据处理程序类的方法URL路径
但如果该方法指定了@Ajax注解,那么返回值可以是任何类型,最终返回的结果会转换成JSON或者XML格式输出到客户端。
@Ajax
@Path("login")
public User login(User
user) throws SQLException {
if (userService.login(user.getName())) {
return user;
} else {
return null;
}
}
前段数据处理程序可以继承org.jtry.framework.net.http.HttpBaseController类
该类可以获取到一些Servlet的基础对象信息
@Path("user")
public class Passport extends HttpBaseController{
要使用网络数据检查器可以实现org.jtry.framework.net.http.entity.ControllerDataChecker接口
public class MyControllerDataChecker implements ControllerDataChecker {
@Override
public boolean inCheck(HttpServletRequest
httpRequest, HttpServletResponse httpResponse, ExecuteResult executeResult)
throws ServletException, IOException {
String userName = httpRequest.getParameter("userName");
if (StringUtil.isEmpty(
userName)) { // 如果请求参数没有用户名那么不允许访问
return false;
}
return true;
}
@Override
public boolean outCheck(HttpServletRequest httpRequest, HttpServletResponse httpResponse, ExecuteResult executeResult)
throws ServletException, IOException {
if (executeResult.getException() instanceof SQLException) {// 如果处理方法发生SQL异常那么直接输出“Error”字符串
executeResult.setResult("Error");
}
if (executeResult.getResult() == null) {// 如果处理方法没有返回值那么就不需要处理网络响应
return false;
}
return true;
}
}
接口包含inCheck与outCheck方法
inCheck方法在请求被处理之前被调用
inCheck方法返回为true那么该请求才允许进入处理方法
inCheck方法返回为false那么该请求直接被忽略,客户端将得不到任何响应
inCheck方法参数包含原始Servlet对象信息和将要传入处理方法的参数值
如果该网络数据检查器被配置为全局的,那么inCheck方法的ExecuteResult参数永远传入为null值
outCheck方法在请求被处理之后被调用
outCheck方法返回为true那么该请求的返回结果才会被响应到客户端
outCheck方法返回为false那么该请求无论处理方法执行结果如何客户端都将得不到任何响应
outCheck方法参数包含原始Servlet对象信息和传入处理方法的参数值与返回的结果值还有可能抛出的异常信息
实现好网络数据检查器之后可以如下使用
在配置类中重写getDataCheckerClass方法可以返回一个网络数据检查器的Class
使用这种方式配置的网络数据检查器为全局生效,每一个请求与响应都会进行拦截
@Override
public Class<? extends ControllerDataChecker> getDataCheckerClass() {
return MyControllerDataChecker.class;
}
在前端数据处理程序类或者方法上的@Path注解中指定网络数据检查器的Class
使用这种方式配置的网络数据检查器会在请求进入该类范围内或者该方法时进行拦截
@Path(value = "user",checker = MyControllerDataChecker.class)
public class Passport{
@Path(value = "login",checker = MyControllerDataChecker.class)
public User login(User user) throws SQLException {
if (userService.login(user.getName())) {
return user;
} else {
return null;
}
}
考虑到网络请求数据的复杂性与业务数据的多样性,为了更好的处理一些数据结构,网络数据处理API也支持自定义类型处理器
要使用类型处理器可以实现org.jtry.framework.net.http.entity.TypeProcessor接口
public class JsonTypeProcessor implements TypeProcessor<JsonObject>{
@Override
public JsonObject handle(String mark, HttpServletRequest httpRequest) {
return JsonUtil.toJsonObject(
httpRequest.getParameter(mark));
}
}
已经实现的类型处理器可以在配置类中的getTypeProcessorClasss方法返回相应的Class
@SuppressWarnings("unchecked")
@Override
public Class<? extends TypeProcessor<?>>[] getTypeProcessorClasss() {
Class<?>[] typeProcessorClasss = new Class<?>[]{
XmlTypeProcessor.class,
JsonTypeProcessor.class,
UserTypeProcessor.class
};
return (Class<? extends TypeProcessor<?>>[]) typeProcessorClasss;
}
凡是前端数据处理程序类中的方法参数使用到的类型
如果有配置相应的类型处理器那么请求过来的数据针对该类型的类型转换将只会使用类型处理器
所以在编写类型处理器的时候请尽量考虑全面,如非必要最好不要针对JAVA基本类型编写类型处理器
@Ajax
@Path("login")
public JsonObject login(JsonObject userJson) throws SQLException {
if (userService.login(userJson.get("name").getAsString())) {
return userJson;
} else {
return null;
}
}
以上例子中login方法的参数JsonObject就会使用类型处理器对请求的数据进行类型转换