一、nutz介绍
Nutz是对于Java程序员来说,除SSH之外的另一个选择。当然,它是开源的,并且是完全免费的。同时也是商业友好的(Licensed under the Apache License, Version 2.0)。主页如下:http://www.nutzam.com/
二、session简单介绍
大家都知道http是无状态的,即:同一个浏览器发送多个请求,服务端并不知道这些请求是来自于同一个浏览器。所以为了使服务端知道这些请求都是来自于同 一个浏览器,用到了session技术。即浏览器第一次发送请求给服务端时,服务端会生成一个sessionId,将该sessionId返回给浏览器, 浏览器将sessionId以cookie的形式保存在客户端,下一次请求该服务器的时候,会将sessionId带过去,服务端可以根据该 sessionId找到在这个session保存的值,并使用该session中保存的值进行一系列的操作。
三、nutz中登录验证的实现方式
1、准备工作
需要有以下准备:/toLogin指向登录页面;/login点击登录后处理登录的方法;/logout指向登出;/test指向一般的业务处理方法。/home指向登录成功后跳转的主页面。
其中:/toLogin和/login是不需要进行登录验证的。
/logout、/test、/home是需要进行登录验证的。
要实现的结果如下:
点击登录/login时,根据用户名/密码进行验证,若登录成功,则将该user保存到session中,并跳转到/home主页;若登录失败,则跳转到/toLogin。
会为其他进行登录验证的方法,实现一个过滤器,在该过滤器中根据session中的user对象是否存在,进行验证,若存在,跳转到/home主页,否则跳转/toLogin页面。
负责登录、登出、及登录主页的类代码如下:
package xxx.xxx.module;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import org.nutz.ioc.loader.annotation.IocBean;import org.nutz.mvc.annotation.At;import org.nutz.mvc.annotation.Filters;import org.nutz.mvc.annotation.Ok;
@IocBeanpublic class LoginDemo {
/**
* 该方法指向登录页面
*/
@Filters //配置Filters之后该方法将不执行过滤器
@At("/toLogin")
@Ok("")//此处配置登录页面的路径
public void toLogin(){
}
/**
* 该方法为登录时的处理方法
* 结果以重定向的方式来跳转。
* 若登录成功,跳转到/home。若登录失败,跳转到/toLogin
* @param req
* @param session
* @return
*/
@At("/login")
@Ok("redirect:${obj==true?'/home':'/toLogin'}")
@Filters
public boolean login(HttpServletRequest req,HttpSession session){
String userName=req.getParameter("name");
String pwd=req.getParameter("pwd");
boolean result=false;//登录成功与否的结果。默认为false
if(!isBlank(userName) && !isBlank(pwd)){
/**
* 此处根据输入的用户名和密码进行数据库查询验证,查看该用户是否存在。
* 一般在用户注册或者新增用户时,都会将密码进行加密。或者将用户名为salt,对密码进行加密并保存到数据库。
* 此时需要对用户名和密码进行相同的加密。并以用户名,加密后的密码为条件,从数据库中查询该用户。
* 若存在,则登录成功。
*/
/**
* 此处user模拟从数据库中查询出的对象
*/
User user=new User();
if(user!=null){
result=true;//此时登录成功
session.setAttribute("user", user);//将该user保存到session中。 }
}
return result;
}
/**
* 登出
* @param session
*/
@At("/logout")
@Ok("redirect:/toLogin")
public void logout(HttpSession session){
session.invalidate();//将该session销毁 }
/**
* 判断str是否为空或"" 若是,返回true。 否则返回false
* @param str
* @return
*/
private boolean isBlank(String str){
if(str==null || "".equals(str.trim())){
return true;
}else{
return false;
}
}
}
2、使用自带的CheckSession.class过滤器
需要在indexModule主入口类中配置过滤器,如下所示:
package xxx.xxx.module;
import org.nutz.mvc.annotation.By;
import org.nutz.mvc.annotation.Filters;
import org.nutz.mvc.filter.CheckSession;
//其中:"user"为session中的属性名。"/toLogin"为若该属性不存在时的处理。此处为跳转到登录页面。
@Filters(@By(type = CheckSession.class,args={"user","/toLogin"}))public class InitModule {
}
nutz中的CheckSession.class源代码如下:
package org.nutz.mvc.filter;import javax.servlet.http.HttpSession;import org.nutz.mvc.ActionContext;import org.nutz.mvc.ActionFilter;import org.nutz.mvc.Mvcs;import org.nutz.mvc.View;import org.nutz.mvc.view.ServerRedirectView;/**
* 检查当前 Session,如果存在某一属性,并且不为 null,则通过 <br>
* 否则,返回一个 ServerRecirectView 到对应 path
* <p>
* 构造函数需要两个参数
* <ul>
* <li>第一个是, 需要检查的属性名称。如果 session 里存在这个属性,则表示通过检查
* <li>第二个是,如果未通过检查,将当前请求转向何处。 一个类似 /yourpath/xxx.xx 的路径
* </ul>
*
* @author zozoh(zozohtnt@gmail.com)
*/public class CheckSession implements ActionFilter {
private String name;
private String path;
public CheckSession(String name, String path) {
this.name = name;
this.path = path;
}
public View match(ActionContext context) {
HttpSession session = Mvcs.getHttpSession(false);
if (session == null || null == session.getAttribute(name))
return new ServerRedirectView(path);
return null;
}
}
3、自定义过滤器
以下为自定义过滤器MyFilter的代码实现:
package xxx.xxx.filters;import javax.servlet.http.HttpSession;import org.nutz.ioc.loader.annotation.IocBean;import org.nutz.mvc.ActionContext;import org.nutz.mvc.ActionFilter;import org.nutz.mvc.View;import org.nutz.mvc.view.ServerRedirectView;
/**
* 自定义的登录验证!
* @author
*
*/
@IocBeanpublic class MyFilter implements ActionFilter{
@Override
public View match(ActionContext actionContext) {
HttpSession session=actionContext.getRequest().getSession();
if(session.getAttribute("user")!=null){
return null;//执行方法 }
//验证不通过时跳转到别的页面!
return new ServerRedirectView("/toLogin.html");
}
}
其实和CheckSession的实现是很类似的。
自定义Filter的配置和内置的CheckSession.class配置类似,配置如下:
@Filters(@By(type = MyFilter.class ,args={"ioc:myFilter"}))
四、注意事项与参考资料
1、 注意事项
被IOC管理的类,均需在类名前添加@IocBean。
如果在登录时需在session中保存多个属性,需把"user",user 用于登录验证的属性放在最后,以防止各种空指针的问题。参考资料:http://wendal.net/399.html
2、参考资料
过滤器相关:http://www.nutzam.com/core/mvc/action_filter.html
入口函数返回的View相关:http://www.nutzam.com/core/mvc/view.html
在Nutz框架中提供Pojo校验(验证)功能的支持
作为java程序员,往往对于spring、struts、Hibernate、iBatis 等国外的开源框架都比较熟悉。它们的确经典,的确强大,的确好用。但是随着时间的发展,这些框架越来越庞大!Hibernate的核心包已经超过2M, spring呢,它现在已经被拆分为 18 个子项目,而且还有继续扩大的趋势。为了一个小小的功能,引入那么一大堆lib包,任谁都得考虑一下吧。
……
这个问题一直存在,直到 Nutz 框架的出现。
一个不到 900K 的开源框架,不仅包含了 ioc、aop、dao、mvc、log,还整合了很多好用的工具类,基本上我们做一个项目需要用到的功能都提供了。
还有要说明的是,它可是国人的开源项目哦,提供全套中文文档,及大量的中文注释。国内的开发人员应该会感到比较亲切吧。
更详细的信息,请参看Nutz的官方网站: http://code.google.com/p/nutz/
Nutz框架虽然提供了很多功能,却独独拉了校验功能的支持。我们知道,一个程序,尤其是Web程序,如果没有服务器端验证,那么将非常容易受到攻击的。
“自己动手,丰衣足食”。既然官方没有提供,那就自己搞一套吧。还好基于Nutz现有的工具类,实现起来并不太复杂。
整个验证框架提供了12种常见的验证形式,且支持自定义正则表达式,基本上可以满足实际的需要。对于有特殊要求的字段验证,允许用户自己定义验证的方法。
校验不仅可以用于Web层,你可以把它用于程序的任何层面(如入库前对pojo 字段值进行验证)。
目前验证框架基于注解,因为对于字段的验证需求一般比较固定,所以同代码一块管理比较方便。当然你也可以扩展它,提供其它形式的验证。如果你有更好的改动,请也一并发我邮箱一份哈。
废话不多说,直接上代码吧。
/**
* 验证支持注解
*
* @author QinerG(QinerG@gmail.com)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.PARAMETER, ElementType.FIELD })
public @interface Validations {
/**
* 必填字段验证规则
*/
public boolean required() default false;
/**
* 手机号验证规则
*/
public boolean mobile() default false;
/**
* 帐号验证规则(字母开头,允许字母数字下划线),常与字串长度验证规则混合使用
*/
public boolean account() default false;
/**
* Email 验证规则
*/
public boolean email() default false;
/**
* QQ 号验证规则
*/
public boolean qq() default false;
/**
* 字串必须为中文验证规则
*/
public boolean chinese() default false;
/**
* 邮政编码验证规则
*/
public boolean post() default false;
/**
* 正则表达式验证规则
*/
public String regex() default "";
/**
* 重复性验证规则。请放置待比较的字段名
*/
public String repeat() default "";
/**
* 字符串最大、最小长度验证规则
*/
public int[] strLen() default {};
/**
* 数值型数据取值范围区间验证规则,兼容 int、long、float、double
*/
public double[] limit() default {};
/**
* 自定义效验规则,可以自行指定验证的方法名称 <br/> 该方法必须是public的,且没有参数返回值为boolean型
*/
public String custom() default "";
/**
* 错误提示语
*/
public String errorMsg();
}
这就是注解类的全部代码。该注解是字段(FIELD)级别的,所以你可以把它声明在pojo的属性上。
比如:
//账号验证规则,与字符串长度区间验证共同作用
@Validations(account = true, strLen = { 3, 16 }, errorMsg = "account")
private String account;
允许多种验证同时声明,errorMsg 是错误提示语,必填。
当pojo需要验证的时候,可以这样写:
Java代码 收藏代码
AnnotationValidation av = new AnnotationValidation();
Errors ers = av.validate(pojo);
验证错误的信息都存放在 Errors 对象中了,你可以调用 getErrorsList() 返回错误列表,或者调用 getErrorsMap() 字段与错误提示语的对应关系。
这时也许你会说,这种调用方法很麻烦。每次验证的时候,都需要创建 AnnotationValidation 的实例,有没有更简单的方法呢?
没错,Nutz提供了 AOP 的支持,这样我们就可以很方便的用它来进行拦截验证了。
下面是拦截器的全部代码:
/**
* 基于注解的验证用拦截器
* <p>
* 该拦截器主要用于方法参数的验证,要求该方法中必须有一个 Errors 类型的参数(允许为空),当验证完成后会向这个参数赋值
*
* @author QinerG(QinerG@gmail.com)
*/
@IocBean(name = "validationInterceptor")
public class ValidationInterceptor extends AbstractMethodInterceptor {
private static AnnotationValidation av = new AnnotationValidation();
/**
* 方法调用前进行拦截,遍历参数进行验证
*/
public boolean beforeInvoke(Object obj, Method method, Object... args) {
Errors es = ValidationUtils.checkArgs(method.getParameterTypes(), args);
if (null != es) {
for (Object argsObj : args) {
if (argsObj instanceof Errors)
continue;
av.validate(argsObj, es);
}
}
return true;
}
}
注意:该拦截器主要用于方法参数的验证,要求该方法中必须有一个 Errors 类型的参数(允许为空),当验证完成后会向这个参数赋值。
有了这个拦截器,就方便多了。只需要在需要提供验证功能的方法前使用 @Aop("validationInterceptor") 声明,例如:
@Aop("validationInterceptor")
public Errors test(Bean bean, Errors es) {
System.out.println(es.errorCount());
return es;
}
之后在调用这个方法的时候,拦截器就会自动执行,并将验证结果注入到参数 Errors 中。下面是 junit测试用例:
@Test
public void testAop() {
Ioc ioc = new NutIoc(new AnnotationIocLoader("org.nutz.validation"));
ServiceDemo sd = ioc.get(ServiceDemo.class);
Bean b = new Bean();
Errors ers = sd.test(b, null);
assertEquals(10, ers.errorCount());
}
这样是不就方便了很多?
应用程序可以用 aop 的方式验证,那么 web 程序呢,也可以这样用吗?那是当然了。在 action 前声明拦截器:
@At("/test")
@Ok("json")
@Aop("validationInterceptor")
public int test(@Param("bean")Bean bean, Errors es) {
System.out.println(Dumps.obj(bean));
if (es != null) {
return es.errorCount();
}
return -99;
}
action 里即可以取到 Errors 对象,并可以对其进行显示等相关处理啦。