<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>誰伴我闖蕩</title>
    <description></description>
    <link>http://cavenaghi.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>遇到prototyte一个很怪异的问题,大家一起讨论一下(已解决，总结一下)</title>
        <author>cavenaghi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cavenaghi.javaeye.com">cavenaghi</a>&nbsp;
          链接：<a href="http://cavenaghi.javaeye.com/blog/67278" style="color:red;">http://cavenaghi.javaeye.com/blog/67278</a>&nbsp;
          发表时间: 2007年04月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">
function Test(url) {
	this.url = url;
	this.str = "want to save responseText";
}

Test.prototype.test = function () {
	alert(this.url); //可以访问到
	alert(this.str); //可以访问到
	var ajax = new Ajax.Request(
		this.url,{	
			method: "get",
			parameters: "time=" +  new Date().getTime(),
			onSuccess: function(req){
				alert(this.url); //可以访问到
				alert(this.str); //无法访问到
				//this.str = responseText; //期待的操作无法执行
			}
		}
	);
};

Event.observe(window, "load", pageLoad, false);
					
var url = "a action url";

function pageLoad(){
         var t = new Test(url);
	t.test();
}
</pre><br /><br />在这里我创建一个页面,并导入了prototype,和上面这段代码.并注册页面的初始化事件<br />初始化事件只是创建一个我自定义的对象,并调用其中的一个方法<br /><br />而当我调用这个方法的时候,<br /><br />alert(this.url);<br />alert(this.str);<br />这些都可以正常访问<br /><br />而在new Ajax.Request内部,却只能访问到this.url.无法访问this.str<br /><br />===================================================================<br /><br />上面是问题的阐述,在cozone_柯中和7thbyte的热心帮助下,终于找到了问题的解决方案<br /><br />===================================================================<br /><br />首先,在prototype中加入下列代码<br /><pre name="code" class="java">
var ClassUtils=Class.create();

ClassUtils.prototype={
        _ClassUtilsName:'ClassUtils',

        initialize:function(){
        },

        /**
         * 给类的每个方法注册一个对类对象的自我引用
         * @param reference 对类对象的引用
         */
        registerFuncSelfLink:function(reference){
                for (var n in reference) {
                var item = reference[n];                        
                if (item instanceof Function)
					item.$ = reference;
            }
        }
}
</pre><br /><br />接着写我新的Test类<br /><pre name="code" class="java">
function Test(url) {
	this.url = url;
	this.str = "want to save responseText";
	new ClassUtils().registerFuncSelfLink(this);
}

Test.prototype.test = function () {
	var funcHolder=arguments.callee.$;
	alert(this.url); //可以访问到
	alert(this.str); //可以访问到
	var ajax = new Ajax.Request(
		this.url,{	
			method: "get",
			parameters: "time=" +  new Date().getTime(),
			onSuccess: function(req){
				alert(funcHolder.url); //可以访问到
				alert(funcHolder.str); //可以访问到
				funcHolder.str = responseText; //期待的操作可执行
			}
		}
	);
};

Event.observe(window, "load", pageLoad, false);
					
var url = "a action url";
vat t = new Test(url);//这次把作用域扩大一下

function pageLoad(){
	t.test();//可以了
}
function getTest(){
	alert(t.str);//可以随时察看一下，确实改变了,呵呵
}
</pre><br /><br />======================================================================<br /><br />至此再次对cozone_柯中和7thbyte的热心帮助表示感谢<br /><br />======================================================================<br /><br />6月21号增加:<br /><br />以上的解决方案太依赖于prototyte了,其实在平时的应用中this指针也是经常遇到的问题<br /><br />现在将这部分独立出来,也可以解决了<br /><pre name="code" class="java">
&lt;script language="javascript">
function registerSelf(reference){
                for (var n in reference) {
                var item = reference[n];                        
                if (item instanceof Function)
					item.$ = reference;
            }
        }

var Book = function(){
	this.name = "book";
}

Book.prototype = {
	main : function(){
		alert(9);
	}
}

var Car = function(name){
	this.name = name;
	registerSelf(this)
}
Car.prototype = {
	getName : function(){
		var book = new Book();
		book.main();
		var self = arguments.callee.$; 
		alert(self.name)
		book.main = function(){
			alert(self.name);
		}
		book.main();
	}
}

function main(){
	var car = new Car("boya");
	car.getName();
}
&lt;/script>

&lt;a href="#" onClick="main();">do&lt;/a></pre><br /><br />======================================================================
          <br/>
          <span style="color:red;">
            <a href="http://cavenaghi.javaeye.com/blog/67278#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 02 Apr 2007 09:04:52 +0800</pubDate>
        <link>http://cavenaghi.javaeye.com/blog/67278</link>
        <guid>http://cavenaghi.javaeye.com/blog/67278</guid>
      </item>
      <item>
        <title>用Applet实现表达式求值 </title>
        <author>cavenaghi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cavenaghi.javaeye.com">cavenaghi</a>&nbsp;
          链接：<a href="http://cavenaghi.javaeye.com/blog/59336" style="color:red;">http://cavenaghi.javaeye.com/blog/59336</a>&nbsp;
          发表时间: 2007年03月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          少了浏览器的支持，Applet在互联网上永远不会有自己的舞台，而我却很酷爱这种把应用程序放到界面里的东东，今天无聊，把以前写过的一个表达式求值的程序，顺手拿Applet改写一下，再让大家体验一下MVC设计模式的应用吧：<br /><br /><br />=======================ExpressionModel===================<br /><pre name="code" class="java">
/*
 *这个就是表达式的模型组件了，它的三个属性，分别代表了它的中则表达式和右则表达式
 *而那两个属性分别是输入的式子和得到的结果
 */
package expression;

import java.text.*;
import java.util.*;

public class ExpressionModel extends Observable
{
 
 private ArrayList&lt;String> middle;
 private ArrayList&lt;String> right;
 private String input, result;

 public ExpressionModel()
 {
  middle = new ArrayList&lt;String>();
  right = new ArrayList&lt;String>();
 }

 //判断一个字符是不是操作符
 private boolean isOperator( String op )
 {
  if( op.equals("+") || op.equals("-") || op.equals("%")
     ||op.equals("*")|| op.equals("/") || op.equals("(")
     ||op.equals(")") )
    return true;
    
  else return false;
 }

 //得到一个操作符的优先级
 private int priority( String op )
 {
  if( op.equals("+") || op.equals("-") || op.equals("(") ) 
   return 1;
  else if( op.equals("*") || op.equals("/") || op.equals("%") ) 
   return 2;
  else 
   return 0;
 }
 

//计算两个数和一个运算符得到的结果
 private String calTwoNumber( String op, String a, String b ) throws Exception
 {
  double x = Double.parseDouble( b );
  double y = Double.parseDouble( a );
  double z = 0;
  
  if( op.equals("+") ) 
   z = x + y;
  else if( op.equals("-") ) 
   z = x - y;
  else if( op.equals("*") ) 
   z = x * y;
  else if( op.equals("/") ) 
   z = x / y;
  else if( op.equals("%") ) 
   z = x % y;
  else 
   z=0;
  
  return Double.toString( z );
 }
 
//将我们输入的中则表达式转换成逆波兰式
 private void turnToRight()
 {
  MyStack stack = new MyStack();
  String op;
  int pos = 0;
  
  StringTokenizer st = new StringTokenizer(input,"+-*/%()",true);
  
  while( st.hasMoreElements() )
   middle.add( st.nextToken() );
  
  while(true)
  {
   if( isOperator( middle.get(pos) ) )
   {
    if( stack.getTop() == -1 || (middle.get(pos)).equals("(") )
    {
     stack.push( middle.get(pos) );
    }
    else
    {
     if( (middle.get(pos)).equals(")") )
     {
      if( !(stack.top()).equals("(") )
      {
       op = stack.pop();
       right.add(op);
      }
     }
     else
     {
      if( priority(middle.get(pos)) &lt;= priority(stack.top()) && stack.getTop() != -1 )
      {
       op = stack.pop();
       if( !op.equals("(") ) 
        right.add(op);
      }
      stack.push( middle.get(pos) );
     }
    }
   }
   else 
    right.add( middle.get(pos) );
   pos++;
   if( pos >= middle.size() ) 
    break;
  }
  
  while( stack.getTop() != -1 )
  {
   op = stack.pop();
   right.add(op);
  }
 }

 private void calculate( String expression ) throws Exception
 {
  input = expression;
  
  turnToRight();
  
  MyStack stack = new MyStack();
  String op1, op2, is = null;
  Iterator&lt;String> it = right.iterator();
  
  while(it.hasNext())
  {
   is = it.next();
   if( isOperator(is) )
   {
    op1 = stack.pop();
    op2 = stack.pop();
    stack.push( calTwoNumber(is,op1,op2) );
   }
   else stack.push(is);
  }
  
  NumberFormat form = NumberFormat.getInstance();
  form.setMaximumFractionDigits(5);
  
  result = input + "=" + form.format( Double.parseDouble( stack.pop() ) );
  
  setChanged();
  notifyObservers();
 }
 
 public void input(String expression) throws Exception
 {
  calculate(expression);
  middle.clear();
  right.clear();
 }
 
 public String getResult(){
  return result;
 }
 
}
</pre><br /><br /><br />===============MyStack==============<br /><br /><pre name="code" class="java">
//我们用到的自己的堆栈
package expression;

import java.util.*;

public class MyStack
{
 
 private LinkedList&lt;String> list;
 private int top;
 
 public MyStack() 
 {
  list = new LinkedList&lt;String>();
  top = -1;
 }
  
 public void push(String value)
 {
  top++;
  list.addFirst(value);
 }
 
 public String pop()
 {
  String temp = list.getFirst();
  top--;
  list.removeFirst();
  return temp;
 }
 
 public String top()
 {
  return list.getFirst();
 }
 
 public int getTop()
 {
  return top;
 }
 
}
</pre><br /><br />===============ExpressionController========------<br /><br /><pre name="code" class="java">
//控制器组件，包括一个输入域和两个按纽

package expression;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ExpressionController extends JPanel 
{
 
 private ExpressionModel expressionModel;   
 private JTextField calTextField;
 
 public ExpressionController( ExpressionModel controllerModel ) {
  
  super();
  
  expressionModel = controllerModel;
  
  calTextField = new JTextField( 15 );
  JButton calButton = new JButton( "计算" );
  JButton delButton = new JButton( "取消" );
  
  calButton.addActionListener(
   new ActionListener() 
   {
    public void actionPerformed( ActionEvent event ) 
    {
     try 
     {
      expressionModel.input( calTextField.getText() );
      calTextField.setText("");
     }
     catch ( Exception exception ) 
     {
      JOptionPane.showMessageDialog ( 
       ExpressionController.this, 
       "请输入有效表达式！", "错误", 
       JOptionPane.ERROR_MESSAGE );
      calTextField.setText("");
     }
    }
   }
  );
  
  delButton.addActionListener(
   new ActionListener() 
   {
    public void actionPerformed( ActionEvent event ) 
    {
     try 
     {
      calTextField.setText("");
     }
     catch ( Exception exception ) 
     {
      calTextField.setText("");
     }
    }
   }
  );
  
  setLayout( new FlowLayout() );
  
  add( calTextField );
  add( calButton );
  add( delButton );
 
 }
 
 public Dimension getPreferredSize() 
 {
  return new Dimension( 320, 40 );
 }
 
 public Dimension getMinimumSize() 
 {
  return getPreferredSize();
 }
 
 public Dimension getMaximumSize() 
 {
  return getPreferredSize();
 }
 
}
</pre><br /><br /><br />================ExpressionView ==================<br /><pre name="code" class="java">
//用来显示结果的视图
package expression;

import java.awt.*;
import java.text.*;
import java.util.*;

import javax.swing.*;
import javax.swing.border.*;

public class ExpressionView extends JPanel implements Observer 
{
 
 private ExpressionModel expressionModel;
 private JLabel display = new JLabel();
 
 public ExpressionView( ExpressionModel model ) {
  
  if( model == null ) 
   throw new NullPointerException();
  
  expressionModel = model;
  expressionModel.addObserver( this );
  
  add( display );
  
  setBackground( Color.white );
  setBorder( new MatteBorder( 1, 1, 1, 1, Color.black ) );
  
 }
 
 public void update( Observable observable, Object object ) 
 {
  display.setText( expressionModel.getResult() );
 }
 
 public Dimension getPreferredSize() 
 {
  return new Dimension( 320, 60 );
 }
 
 public Dimension getMinimumSize() 
 {
  return getPreferredSize();
 }
 
 public Dimension getMaximumSize() 
 {
  return getPreferredSize();
 }
 
 
}
</pre><br /><br /><br /><br />===================Expression=====================<br /><br />//最后把这些组装到这里吧<br /><pre name="code" class="java">

package expression;

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.border.*;

public class Expression extends JApplet 
{
   
 public void init() 
 {
  ExpressionModel model = new ExpressionModel();
  ExpressionView view = new ExpressionView( model );
  ExpressionController controller = new ExpressionController( model );
  
  Container contentPane = getContentPane();
  contentPane.add( view, BorderLayout.CENTER );
  contentPane.add( controller, BorderLayout.SOUTH );
  
  setSize( 320, 100 );
  
 }
   
}
</pre><br /><br />把这几个类打包到一个jar文件后，再创建个htm文件来访问它<br /><br /><pre name="code" class="java">
&lt;object
    classid = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
    codebase = "http://java.sun.com/update/1.5.0/jinstall-1_5-windows-i586.cab#Version=5,0,0,5"
    WIDTH = 320 HEIGHT = 100 >
    &lt;PARAM NAME = CODE VALUE = "expression.Expression" >
    &lt;PARAM NAME = ARCHIVE VALUE = "expression.jar" >
    &lt;param name = "type" value = "application/x-java-applet;version=1.5">
    &lt;param name = "scriptable" value = "false">
&lt;/object>
</pre><br />这样就行了，不过你的机器需要安装jre 5
          <br/>
          <span style="color:red;">
            <a href="http://cavenaghi.javaeye.com/blog/59336#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 12 Mar 2007 17:25:22 +0800</pubDate>
        <link>http://cavenaghi.javaeye.com/blog/59336</link>
        <guid>http://cavenaghi.javaeye.com/blog/59336</guid>
      </item>
      <item>
        <title>Spring+Hibernate+Acegi 的初次体验 </title>
        <author>cavenaghi</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cavenaghi.javaeye.com">cavenaghi</a>&nbsp;
          链接：<a href="http://cavenaghi.javaeye.com/blog/59334" style="color:red;">http://cavenaghi.javaeye.com/blog/59334</a>&nbsp;
          发表时间: 2007年03月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          到现在我也没有弄明白Acegi里面很多的功能,刚刚开始学的时候我就已经被它那繁琐的配置震慑住了，不过当我动起手来一步步实现的时候,才发现其实它远没有那么难,当然随着学习的深入,会渐渐再发现这一点吧,现在就让我们初学者一切体验Acegi的功能吧!<br /><br />还以我传统的例子为例:<br />毕业设计选题系统,三种角色:教师,学生,管理员,我想让他们的登陆都在一个界面下自动识别,而无需进行身份选择,登陆后,他们将分别到各自的admin.jsp,stu.jsp,teacher.jsp<br />在数据库中的表结构如下(很多属性略):<br />id--- user---password--type---about<br /><br />type是用来存储用户的类别,分别有a,t,s分别对应三种角色<br />about对应的是acegi里所需要的enable,用户是否可用<br /><br />在model里,我们采用了继承关系:<br /><br />父类user:<br /><pre name="code" class="java">
package subject.model;

public abstract class User extends BaseObject
{
 private Integer id;
 private String user;
 private String password;
 private String name;
 private String telphone;

  //set and get method 
 //这个是用来反映用户角色的关键函数,在子类实现,从而实现多态
 public abstract String getType(); 
}
</pre><br /><br />子类的实现:<br />======================<br /><pre name="code" class="java">
package subject.model;

import subject.Constants;

public class Teacher extends User
{
 private String level;         //教师的职称

//set and get method

 public String getType()
 {
  return Constants.TEACHER;
 }
}
</pre><br />================<br /><pre name="code" class="java">
package subject.model;

import subject.Constants;

public class Student extends User
{
 private static final long serialVersionUID = 1L;

 private SchoolClass schoolClass;         //学生的班级
 private String sn;             //学生的学号

//set and get method
 
 public String getType()
 {
  return Constants.STUDENT;
 }
}
</pre><br />=================<br /><pre name="code" class="java">
package subject.model;

import subject.Constants;

public class Admin extends User
{
 private String grade;           //管理员的级别
//set and get method

 public String getType()
 {
  return Constants.ADMIN;
 }
}
</pre><br /><br />对于三者所共有的属性在数据库里,都存在一个字段,而依据不同的角色拥有不同的含义,学生的班级则存放在了about里,只要学生有班级,他就able,否则就enable了!而管理员和教师则默认为1!<br /><br />这种是属于一个继承树存放在一个表的情况,Hibernate的配置如下:<br /><pre name="code" class="java">
&lt;hibernate-mapping>

 &lt;class name="subject.model.User" discriminator-value="not null">

  &lt;id name="id">
   &lt;generator class="increment" />
  &lt;/id>
  
  &lt;discriminator column="type" type="character" />
  
  &lt;property name="user" />
  &lt;property name="password" />
  &lt;property name="name" />
  &lt;property name="telphone" />

  &lt;subclass name="subject.model.Admin" discriminator-value="a">
   &lt;property name="grade" column="sn" />
  &lt;/subclass>
  
  &lt;subclass name="subject.model.Teacher" discriminator-value="t">
   &lt;property name="level" column="sn" />
  &lt;/subclass>
  
  &lt;subclass name="subject.model.Student" discriminator-value="s">
   
   &lt;property name="sn" />
   
   &lt;many-to-one name="schoolClass" class="subject.model.SchoolClass" 
    column="about" update="false" insert="false" />
    
  &lt;/subclass>

 &lt;/class>

&lt;/hibernate-mapping>
</pre><br /><br />=============================================<br />上面的这些都是模型的基础,下面再讲怎么样配合Spring和Acegi实现系统的安全与登陆<br />在Spring中Hibernate的配置只介绍不说明:<br /><pre name="code" class="java">
&lt;!-- 定义DBCP数据源 -->
 &lt;bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  &lt;property name="driverClassName" value="com.mysql.jdbc.Driver" />
  &lt;property name="url" value="jdbc:mysql://localhost/subject?useUnicode=true&characterEncoding=gbk" />
  &lt;property name="username" value="root" />
  &lt;property name="password" value="" />
  &lt;property name="maxActive" value="100" />
  &lt;property name="maxIdle" value="30" />
  &lt;property name="maxWait" value="1000" />
  &lt;property name="defaultAutoCommit" value="true" />
  &lt;property name="removeAbandoned" value="true" />
  &lt;property name="removeAbandonedTimeout" value="60" />
 &lt;/bean>

 &lt;!-- Hibernate -->
 &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
  &lt;property name="dataSource" ref="dataSource" />
  &lt;property name="mappingResources">
   &lt;list>
    &lt;value>subject/model/User.hbm.xml&lt;/value>
   &lt;/list>
  &lt;/property>
  &lt;property name="hibernateProperties">
   &lt;props>
    &lt;prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect&lt;/prop>
   &lt;/props>
  &lt;/property>
 &lt;/bean>

 &lt;bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  &lt;property name="sessionFactory" ref="sessionFactory" />
 &lt;/bean>

&lt;!-- Dao对象 -->
&lt;bean id="userDao" class="subject.dao.hibernate.UserDaoImpl">
  &lt;property name="sessionFactory" ref="sessionFactory" />
 &lt;/bean>

&lt;!-- 业务逻辑 -->
 &lt;bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
  &lt;property name="transactionManager" ref="transactionManager" />
  &lt;property name="transactionAttributes">
   &lt;props>
    &lt;prop key="save*">PROPAGATION_REQUIRED&lt;/prop>
    &lt;prop key="remove*">PROPAGATION_REQUIRED&lt;/prop>
    &lt;prop key="get*">PROPAGATION_REQUIRED,readOnly&lt;/prop>
   &lt;/props>
  &lt;/property>
 &lt;/bean>

&lt;bean id="userManager" parent="txProxyTemplate">
  &lt;property name="target">
   &lt;bean class="subject.service.impl.UserManagerImpl">
    &lt;property name="userDao" ref="userDao" />
   &lt;/bean>
  &lt;/property>
 &lt;/bean>

&lt;!-- Struts -->
 &lt;bean name="/user" class="subject.web.action.UserAction" singleton="false">
  &lt;property name="userManager">
   &lt;ref bean="userManager" />
  &lt;/property>
 &lt;/bean>
</pre><br />==================<br />上面具体的不用了解,无非就是调用和数据库的操作,<br />下面就要对Acegi进行声明了:<br />我不用Ctrl+c和Ctrl+V的方式对Acegi进行介绍,没有意义,随便google就一大堆<br />我们想主要在这样的系统中需要的安全策略都有哪些?<br />1.用户的登陆<br />2.防止多个用户登陆一个帐号<br />3.用户的注销<br />4.防止非法用户的访问<br /><br />我这个程序所涉及到的只有这些,下面就进行说明:<br /><br />在web.xml的声明:<br /><pre name="code" class="java">
&lt;!-- Acegi安全控制 Filter 配置 -->
    &lt;filter>
        &lt;filter-name>securityFilter&lt;/filter-name>
        &lt;filter-class>org.acegisecurity.util.FilterToBeanProxy&lt;/filter-class>
        &lt;init-param>
            &lt;param-name>targetClass&lt;/param-name>
            &lt;param-value>org.acegisecurity.util.FilterChainProxy&lt;/param-value>
        &lt;/init-param>
    &lt;/filter>
    
    &lt;filter-mapping>
        &lt;filter-name>securityFilter&lt;/filter-name>
        &lt;url-pattern>/*&lt;/url-pattern>
    &lt;/filter-mapping>
</pre><br /><br />Acegi通过实现了Filter接口的FilterToBeanProxy提供一种特殊的使用Servlet Filter的方式，它委托Spring中的Bean -- FilterChainProxy来完成过滤功能，这样就简化了web.xml的配置，并且利用Spring IOC的优势。FilterChainProxy包含了处理认证过程的filter列表，每个filter都有各自的功能。<br /><br /><pre name="code" class="java">
&lt;!-- ======================== FILTER CHAIN ======================= -->
 &lt;bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
  &lt;property name="filterInvocationDefinitionSource">
   &lt;value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON 
    PATTERN_TYPE_APACHE_ANT
    
    /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,
         securityContextHolderAwareRequestFilter,exceptionTranslationFilter,filterInvocationInterceptor
   &lt;/value>
  &lt;/property>
 &lt;/bean>
</pre><br /><br />大体上先介绍一下:<br />httpSessionContextIntegrationFilter:每次request前 HttpSessionContextIntegrationFilter从Session中获取Authentication对象，在request完后, 又把Authentication对象保存到Session中供下次request使用,此filter必须其他Acegi filter前使用，使之能跨越多个请求。<br />logoutFilter:用户的注销<br />authenticationProcessingFilter:处理登陆请求<br />exceptionTranslationFilter:异常转换过滤器<br />filterInvocationInterceptor:在访问前进行权限检查<br /><br />这些就犹如在web.xml声明一系列的过滤器,不过当把他们都声明在spring中就可以享受Spring给我们带来的方便了。<br /><br />下面就是对这些过滤器的具体声明：<br />只对有用的地方进行声明，别的地方几乎都是默许的<br /><pre name="code" class="java">
&lt;!-- ======================== FILTER ======================= -->
 &lt;bean id="httpSessionContextIntegrationFilter" 
  class="org.acegisecurity.context.HttpSessionContextIntegrationFilter" />

 &lt;bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
  &lt;constructor-arg value="/index.htm" />             离开后所转向的位置
  &lt;constructor-arg>
            &lt;list>
                &lt;bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
            &lt;/list>
        &lt;/constructor-arg>
  &lt;property name="filterProcessesUrl" value="/logout.htm" />        定义用户注销的地址，
 &lt;/bean>

</pre><br />下面的这个过滤器，我们根据自己的需求有了自己的实现：<br /><pre name="code" class="java">
 &lt;bean id="authenticationProcessingFilter" class="subject.web.filter.UserAuthenticationProcessingFilter">
  &lt;property name="authenticationManager" ref="authenticationManager"/>  下面会介绍的用来起到认证管理的作用
  &lt;property name="authenticationFailureUrl" value="/login.htm?error=wrong"/>  登陆失败的地址
  &lt;property name="defaultTargetUrl" value="/login.htm"/>       登陆成功的地址
  &lt;property name="filterProcessesUrl" value="/j_security_check"/>      登陆请求的地址
  &lt;property name="userManager" ref="userManager"/>        自己添加的属性，这样就可以访问到我们的业务逻辑
  &lt;property name="exceptionMappings">   出现异常所对应的地址
            &lt;value>
                org.acegisecurity.AuthenticationException=/login.htm?error=fail     登陆失败                org.acegisecurity.concurrent.ConcurrentLoginException=/login.htm?error=too        已登陆了
            &lt;/value>
        &lt;/property>
 &lt;/bean>
 
 &lt;bean id="securityContextHolderAwareRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/>

 &lt;bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
  &lt;property name="authenticationEntryPoint">
   &lt;bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
    &lt;property name="loginFormUrl" value="/login.htm?error=please"/>//如果用户没登陆就想访问，先到这里登陆吧
    &lt;property name="forceHttps" value="false"/>
   &lt;/bean>
  &lt;/property>
 &lt;/bean>
 
 &lt;bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
  &lt;property name="authenticationManager" ref="authenticationManager"/>       认证服务
  &lt;property name="accessDecisionManager">
   &lt;bean class="org.acegisecurity.vote.AffirmativeBased">
    &lt;property name="allowIfAllAbstainDecisions" value="false"/>
    &lt;property name="decisionVoters">
     &lt;list>
      &lt;bean class="org.acegisecurity.vote.RoleVoter">
                    &lt;property name="rolePrefix" value=""/>         //这里定义数据库中存放的角色和我们在这里声明的角色间是否需要加个前缀？我没加
                &lt;/bean>
     &lt;/list>
    &lt;/property>
   &lt;/bean>
  &lt;/property>
  &lt;property name="objectDefinitionSource">
            &lt;value>
                PATTERN_TYPE_APACHE_ANT
                
                /admin.htm*=a         这里就是数据库中对应的tyep a
                /student*=s           由于没有前缀和数据库里一样
                /teacher*=t
            &lt;/value>
        &lt;/property>
 &lt;/bean>
 
 &lt;bean id="loggerListener"
          class="org.acegisecurity.event.authentication.LoggerListener"/>       记录事件

下面就要说明我们的认证服务了，其起到的关键作用就是用来保证用户登陆身份的验证：

它将验证的功能委托给多个Provider，并通过遍历Providers, 以保证获取不同来源的身份认证，若某个Provider能成功确认当前用户的身份，authenticate()方法会返回一个完整的包含用户授权信息的Authentication对象，否则会抛出一个AuthenticationException。

先声明一个管理器吧，在上面的过滤器中都已经用到过了
&lt;!-- ======================== AUTHENTICATION ======================= -->
 &lt;bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
  &lt;property name="providers">
   &lt;list>
    &lt;ref local="daoAuthenticationProvider" />   我仅仅用到 从数据库中读取用户信息验证身份
   &lt;/list>
  &lt;/property>
  &lt;property name="sessionController">
   &lt;bean id="concurrentSessionController" 
    class="org.acegisecurity.concurrent.ConcurrentSessionControllerImpl">
    &lt;property name="maximumSessions">
     &lt;value>1&lt;/value>每个用户同时登陆一位
    &lt;/property>
    &lt;property name="sessionRegistry">
     &lt;bean id="sessionRegistry" class="org.acegisecurity.concurrent.SessionRegistryImpl" />
    &lt;/property>
    &lt;property name="exceptionIfMaximumExceeded" value="true" />
   &lt;/bean>
  &lt;/property>
 &lt;/bean>
 来实现唯一的一个Provider，从数据库验证身份
 &lt;bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
  &lt;property name="userDetailsService">
   &lt;bean id="jdbcDaoImpl"
            class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
          &lt;property name="dataSource" ref="dataSource"/>
          &lt;property name="usersByUsernameQuery">
              &lt;value>
                  select user,password,about from user where user = ?        查找用户的查询语句，只需要把你数据库中的用户和密码以及enable相对应上就行
              &lt;/value>
          &lt;/property>
          &lt;property name="authoritiesByUsernameQuery">
              &lt;value>
                  select user,type from user where user = ?           这里就是把用户和权限对应上，在appfuse中用的两个表，我都放一个表里了，所以就用这一个就行问题的关键是要让它能找到两个字段，构成一个对象
              &lt;/value>
          &lt;/property>
      &lt;/bean>
  &lt;/property>
  &lt;property name="userCache"> 缓存都这么写：
   &lt;bean class="org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
    &lt;property name="cache">
     &lt;bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
      &lt;property name="cacheManager">
       &lt;bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
      &lt;/property>
      &lt;property name="cacheName" value="userCache"/>
     &lt;/bean>
    &lt;/property>
   &lt;/bean>
  &lt;/property>
 &lt;/bean>
</pre><br />==============<br />对于上面登陆请求的处理器我借鉴了springSide，实现的方法如下：<br /><pre name="code" class="java">
package subject.web.filter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.acegisecurity.Authentication;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
import org.acegisecurity.userdetails.UserDetails;

import subject.Constants;
import subject.model.User;
import subject.service.UserManager;

public class UserAuthenticationProcessingFilter extends
  AuthenticationProcessingFilter
{
 private UserManager userManager;

 public void setUserManager( UserManager userManager )
 {
  this.userManager = userManager;
 }

 protected boolean requiresAuthentication( HttpServletRequest request ,
   HttpServletResponse response )
 {
  boolean requiresAuth = super.requiresAuthentication( request, response );
  HttpSession httpSession = null;
  try
  {
   httpSession = request.getSession( false );
  }
  catch ( IllegalStateException ignored )
  {
  }
  if ( httpSession != null )
  {
   if ( httpSession.getAttribute( Constants.USER ) == null )
   {
    if ( !requiresAuth )
    {
     SecurityContext sc = SecurityContextHolder.getContext();
     Authentication auth = sc.getAuthentication();
     if ( auth != null
       && auth.getPrincipal() instanceof UserDetails )
     {
      UserDetails ud = (UserDetails) auth.getPrincipal();//上面声明的sql无非就是要包装成这个对象
      User user = userManager.getUser( ud.getUsername() );从业务逻辑里找到用户，放到session里
      httpSession.setAttribute( Constants.USER, user );
     }
    }
   }
  }
  return requiresAuth;
 }
}
</pre><br /><br />在看看我的login.htm在登陆成功时是怎么工作的吧？<br /><pre name="code" class="java">
public class UserAction extends BaseAction
{
 private UserManager mgr;

 public void setUserManager( UserManager mgr )
 {
  this.mgr = mgr;
 }

 public ActionForward login( ActionMapping mapping , ActionForm form ,
   HttpServletRequest request , HttpServletResponse response )
   throws Exception
 {
  User user = (User) getSessionObject( request, Constants.USER );
  ActionMessages msg = new ActionMessages();
  if ( user != null )
  {
   return new ActionForward(  user.getType() + ".htm", true );成功就去type.htm
  }
  else
  {
   String error = getParameter( request, Constants.ERROR );
   if ( error != null )对于不同的错误，都加以提示
   {
    if ( error.equalsIgnoreCase( "wrong" ) )
     msg.add( "msg", new ActionMessage( "fail.login.wrong" ) );
    else if ( error.equalsIgnoreCase( "too" ) )
     msg.add( "msg", new ActionMessage( "fail.login.too" ) );
    else if ( error.equalsIgnoreCase( "fail" ) )
     msg.add( "msg", new ActionMessage( "fail.login.fail" ) );
    else
     msg.add( "msg", new ActionMessage( "fail.login.please" ) );
   }
   else
    msg.add( "msg", new ActionMessage( "fail.login.please" ) );
  }
  saveErrors( request, msg );
  return mapping.findForward( "fail" );
 }

}
</pre><br /><br />当然，Acegi需要介绍的东西太多了，我只把我这次认为有必要解释的东西写在了上面让大家来参考，作为能google到的东西，比如对于认证的方式还有很多，我就没有详细的介绍，在学习Acegi过程中，把它自带的例子弄清楚很关键，希望大家一起学习一起共勉！
          <br/>
          <span style="color:red;">
            <a href="http://cavenaghi.javaeye.com/blog/59334#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 12 Mar 2007 17:20:45 +0800</pubDate>
        <link>http://cavenaghi.javaeye.com/blog/59334</link>
        <guid>http://cavenaghi.javaeye.com/blog/59334</guid>
      </item>
  </channel>
</rss>