分类: Java

  • java中实现HashMap中的按照key的字典顺序排序输出

     HashMap<String, String> maptest =new  HashMap<String, String>();
    		 maptest.put("1天","day1");
    		 maptest.put("5天","day5");
    		 maptest.put("4天","day4");
    		 maptest.put("2天","day2");
    		 maptest.put("3天","day3");
    		 
    		 Collection<String> keyset= maptest.keySet();
    		 List<String> list = new ArrayList<String>(keyset);
    		 
    		 //对key键值按字典升序排序
    		 Collections.sort(list);
    		 
    		 
    		 for (int i = 0; i < list.size(); i++) {
    			 System.out.println("key键---值: "+list.get(i)+","+maptest.get(list.get(i)));
    		 }

     

  • Exception occurred during processing request: Cannot create XmlPullParser 解决方法

    严重: Exception occurred during processing request: Cannot create XmlPullParser
    com.thoughtworks.xstream.io.StreamException: Cannot create XmlPullParser
    	at com.thoughtworks.xstream.io.xml.AbstractXppDriver.createReader(AbstractXppDriver.java:56)
    	at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1040)
    	at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1031)
    	at cn.com.sway.cms.web.weixin.action.TokenAction.token(TokenAction.java:109)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:606)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:446)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:285)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:248)
    	at cn.com.sway.cms.interceptor.GlobalInterceptor.intercept(GlobalInterceptor.java:116)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:176)
    	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
    	at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
    	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:238)
    	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:238)
    	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:75)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:90)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:252)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
    	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:176)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:187)
    	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
    	at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
    	at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:544)
    	at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
    	at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    	at org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:119)
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    	at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:122)
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java)
    	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    	at org.apache.catalina.core.StandardHostValve.__invoke(StandardHostValve.java:170)
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java)
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
    	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
    	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2441)
    	at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2430)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    	at java.lang.Thread.run(Thread.java:744)

     

    原因:缺少jar包

    解决方法:

    使用xStream需要引入以下3个jar包
    xstream-1.4.7.jar
    xmlpull_1_1_3_4c.jar
    kxml2-2.3.0.jar

     

  • Struts2中使用execAndWait后,在 Action中调用getXXX()方法报告java.lang.NullPointerException异常的原因和解决方法

    使用 Struts2 编写页面,遇到一个要长时间运行的接口,因此增加了一个execAndWait ,结果在 Action 中调用 getContext()的时候报告异常

    1 ActionContext context = ActionContext.getContext();
    2 ServletContext servletContext = (ServletContext) context.get(ServletActionContext.SERVLET_CONTEXT);  //抛空指针异常
    3 String rootPath = servletContext.getRealPath("/");

    查询了很多评论,最终找到原因跟解决方案,具体解释在 http://stackoverflow.com/questions/16692658/execandwait-interceptor-not-redirecting-to-success-page-after-waiting。大致意思为:execAndWait 会导致执行的Action 在另外一个线程中被执行,而getText 依赖 ActionContext ,他从 ActionContext 中获得当前的Locale 从而根据语言的不同加载不同的文字,可是,由于ActionContext 是ThreadLocal 的,而execAndWait 新开线程的时候并没有把父线程的ActionContext 传递给子线程 结果导致在新开的子线程中的ActionContext中的数据都是null ,因此出现异常信息就不足为怪了。

    解决方法如下:需要重载两个类,来解决这个问题

    ActionInvocationEx.java

    package byrs.rms.interceptors;
    
    import com.opensymphony.xwork2.ActionContext;
    import com.opensymphony.xwork2.ActionEventListener;
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.ActionProxy;
    import com.opensymphony.xwork2.Result;
    import com.opensymphony.xwork2.interceptor.PreResultListener;
    import com.opensymphony.xwork2.util.ValueStack;
    
    public class ActionInvocationEx implements ActionInvocation {
    
        /**
         * 
         */
        private static final long serialVersionUID = 2434502343414625665L;
    
        private final ActionInvocation mActionInvocation;
    
        private final ActionContext context;
    
        public ActionInvocationEx(ActionInvocation aActionInvocation,ActionContext aContext)
        {
            mActionInvocation = aActionInvocation;
            context = aContext;
        }
    
        public Object getAction() {
            return mActionInvocation.getAction();
        }
    
        public boolean isExecuted() {
            return mActionInvocation.isExecuted();
        }
    
        public ActionContext getInvocationContext() {
            return mActionInvocation.getInvocationContext();
        }
    
        public ActionProxy getProxy() {
            return mActionInvocation.getProxy();
        }
    
        public Result getResult() throws Exception {
            return mActionInvocation.getResult();
        }
    
        public String getResultCode() {
            return mActionInvocation.getResultCode();
        }
    
        public void setResultCode(String resultCode) {
            mActionInvocation.setResultCode(resultCode);
        }
    
        public ValueStack getStack() {
            return mActionInvocation.getStack();
        }
    
        public void addPreResultListener(PreResultListener listener) {
            mActionInvocation.addPreResultListener(listener);
        }
    
        public String invoke() throws Exception {
            return mActionInvocation.invoke();
        }
    
        public String invokeActionOnly() throws Exception {
            return mActionInvocation.invokeActionOnly();
        }
    
        public void setActionEventListener(ActionEventListener listener) {
            mActionInvocation.setActionEventListener(listener);
        }
    
        public void init(ActionProxy proxy) {
            mActionInvocation.init(proxy);
        }
    
        public ActionInvocation serialize() {
            return mActionInvocation.serialize();
        }
    
        public ActionInvocation deserialize(ActionContext actionContext) {
            return mActionInvocation.deserialize(actionContext);
        }
    
        /**
         * @return the context
         */
        public ActionContext getContext() {
            return context;
        }
    
    }

     

    ExecAndWaitInterceptorEx.java

    package byrs.rms.interceptors;
    
    import org.apache.struts2.interceptor.BackgroundProcess;
    import org.apache.struts2.interceptor.ExecuteAndWaitInterceptor;
    
    import com.opensymphony.xwork2.ActionContext;
    import com.opensymphony.xwork2.ActionInvocation;
    
    public class ExecAndWaitInterceptorEx extends ExecuteAndWaitInterceptor {
    
        /**
         * 
         */
        private static final long serialVersionUID = 8829373762598564300L;
        
        /**
         * {@inheritDoc}
         */
        @Override
        protected BackgroundProcess getNewBackgroundProcess(String arg0, ActionInvocation arg1, int arg2) {
            ActionInvocationEx aActionInvocationEx = new ActionInvocationEx(arg1,ActionContext.getContext());
            return new BackgroundProcessEx(arg0, aActionInvocationEx, arg2);
        }
    
        private class BackgroundProcessEx extends BackgroundProcess {
            public BackgroundProcessEx(String threadName,
                    ActionInvocation invocation, int threadPriority) {
                super(threadName, invocation, threadPriority);
            }
    
            private static final long serialVersionUID = -9069896828432838638L;
            /**
             * {@inheritDoc}
             * @throws InterruptedException 
             */
            @Override
            protected void beforeInvocation() throws InterruptedException {
                ActionInvocationEx aActionInvocationEx = (ActionInvocationEx)this.invocation;
                ActionContext context = aActionInvocationEx.getContext();
                ActionContext.setContext(context);
            }
    
            /**
             * {@inheritDoc}
             */
           @Override
            protected void afterInvocation() {
                ActionContext.setContext(null);
            }
    
        }
    
    }

     

    然后在struts.xml中覆盖默认拦截器即可

    <interceptors > 
    	<interceptor name="execAndWait" class="byrs.rms.interceptors.ExecAndWaitInterceptorEx"/> 
    </interceptors >

    参考自:http://www.mobibrw.com/?p=1046

  • 在struts2上获取包含参数的完整的url

    Map map = request.getParameterMap();
    Iterator it = map.keySet().iterator();
    String paramStr = "";
    while(it.hasNext()){
    	String key = it.next().toString();
    	String value = request.getParameter(key);
    	paramStr += key + "=" + value + "&";
    }
    //完整的请求
    System.out.println(request.getRequestURL()+"?"+paramStr);

     

  • Linux环境 Mysql+Hibernate command denied to user 错误

    栈头的样子:

    com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: SELECT command denied to user ‘XXX’@’XXX.XXX.XXX.XXX’ for table ‘XXX’

    1.可能是权限原因

    2.如果权限没有问题,并且是使用hibernate框架的前提下。可能是你的xml映射文件或者是annotation映射类里面设置了一个默认的schema名称,而叫这个名的schema在当前数据库不存在。这个shema变量叫catalog,均在xml和映射类中的头部,将其去掉即可以解决问题。

  • 用java清除字符串里的样式标签

    java 清除 HTML标签格式、CSS 样式

    JAVA代码可以这样写:

    public static String delTagsFContent(String content){
    String strHtml="";//HTML文本代码
    String strClear=strHtml.replaceAll( ".*?(.*?)<\\/body>", "$1"); //读出body内里所有内容
    strClear=strClear.replaceAll("</?[^/?(br)|(p)][^><]*>","");//保留br标签和p标签
    system.out.println(strClear);//输出结果
    }

    如果要保留IMG标签的话,正则表达式就是:</?[^/?(img)][^><]*>

    如果想保留更多的标签,只在正则表达式改一下就可以了, </?[^/?(img)|(p)][^><]*> 这个保留(这里写的保留了img,p这两个标签)你指定的标签,其他的(包括font)全去掉, 如果你还有其他的标签想保留,直接在里面加一个 |(xxx)就行了

    想去掉所有的标签的话正则表达式为:</?[a-zA-Z]+[^><]*>

  • JDK安装与环境变量配置

    安装JDK 选择安装目录 安装过程中会出现两次 安装提示 。第一次是安装 jdk ,第二次是安装 jre 。建议两个都安装在同一个java文件夹中的不同文件夹中。(不能都安装在java文件夹的根目录下,jdk和jre安装在同一文件夹会出错)

    1:安装jdk 随意选择目录 只需把默认安装目录 \java 之前的目录修改即可
    2:安装jre→更改→ \java 之前目录和安装 jdk 目录相同即可
    注:若无安装目录要求,可全默认设置。无需做任何修改,两次均直接点下一步。

    安装完JDK后配置环境变量  计算机→属性→高级系统设置→高级→环境变量

    系统变量→新建 JAVA_HOME 变量 。
    变量值填写jdk的安装目录(本人是 E:\Java\jdk1.7.0)

    系统变量→寻找 Path 变量→编辑
    在变量值最后输入 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
    (注意原来Path的变量值末尾有没有;号,如果没有,先输入;号再输入上面的代码)

    系统变量→新建 CLASSPATH 变量
    变量值填写   .%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar(注意最前面有一点)
    系统变量配置完毕

    检验是否配置成功 运行cmd 输入 java -version (java 和 -version 之间有空格)

  • 【转】JPEGImageEncoder编译有关问题

    解决:Access restriction: The type JPEGImageEncoder is not accessible due to restriction

    在Eclipse中处理图片,需要引入两个包:
    import com.sun.image.codec.jpeg.JPEGCodec;
    import com.sun.image.codec.jpeg.JPEGImageEncoder;
    报错:
    Access restriction: The type JPEGImageEncoder is not accessible due to restriction on required library C:\Java\jre1.6.0_07\lib\rt.jar

    此时解决办法:
    Eclipse 默认把这些受访问限制的API设成了ERROR。

    只 要把Windows-Preferences-Java-Complicer- Errors/Warnings里面的Deprecated and restricted API中的Forbidden references(access rules)选为Warning就可以编译通过

  • Java输出JVM和操作系统的相关属性

    方法就是利用Java提供的util包中的Properties类:

    import java.util.*;  
    
    public class YourJavaProperties {  
        public static void main(String args[]){  
            Properties props=System.getProperties();   
    
            System.out.println("Java的运行环境版本:"+props.getProperty("java.version"));  
            System.out.println("Java的运行环境供应商:"+props.getProperty("java.vendor"));  
            System.out.println("Java供应商的URL:"+props.getProperty("java.vendor.url"));  
            System.out.println("Java的安装路径:"+props.getProperty("java.home"));  
            System.out.println("Java的虚拟机规范版本:"+props.getProperty("java.vm.specification.version"));  
            System.out.println("Java的虚拟机规范供应商:"+props.getProperty("java.vm.specification.vendor"));  
            System.out.println("Java的虚拟机规范名称:"+props.getProperty("java.vm.specification.name"));  
            System.out.println("Java的虚拟机实现版本:"+props.getProperty("java.vm.version"));  
            System.out.println("Java的虚拟机实现供应商:"+props.getProperty("java.vm.vendor"));  
            System.out.println("Java的虚拟机实现名称:"+props.getProperty("java.vm.name"));  
            System.out.println("Java运行时环境规范版本:"+props.getProperty("java.specification.version"));  
            System.out.println("Java运行时环境规范供应商:"+props.getProperty("java.specification.vender"));  
            System.out.println("Java运行时环境规范名称:"+props.getProperty("java.specification.name"));  
            System.out.println("Java的类格式版本号:"+props.getProperty("java.class.version"));  
            System.out.println("Java的类路径:"+props.getProperty("java.class.path"));  
            System.out.println("加载库时搜索的路径列表:"+props.getProperty("java.library.path"));  
            System.out.println("默认的临时文件路径:"+props.getProperty("java.io.tmpdir"));  
            System.out.println("一个或多个扩展目录的路径:"+props.getProperty("java.ext.dirs"));  
            System.out.println("操作系统的名称:"+props.getProperty("os.name"));  
            System.out.println("操作系统的构架:"+props.getProperty("os.arch"));  
            System.out.println("操作系统的版本:"+props.getProperty("os.version"));  
            System.out.println("文件分隔符:"+props.getProperty("file.separator"));   //在 unix 系统中是"/"  
            System.out.println("路径分隔符:"+props.getProperty("path.separator"));   //在 unix 系统中是":"  
            System.out.println("行分隔符:"+props.getProperty("line.separator"));   //在 unix 系统中是"/n"  
            System.out.println("用户的账户名称:"+props.getProperty("user.name"));  
            System.out.println("用户的主目录:"+props.getProperty("user.home"));  
            System.out.println("用户的当前工作目录:"+props.getProperty("user.dir"));  
        }  
    }

    输出如下:

    Java的运行环境版本:1.6.0_15  
    Java的运行环境供应商:Sun Microsystems Inc.  
    Java供应商的URL:http://java.sun.com/  
    Java的安装路径:C:/Java/jre6  
    Java的虚拟机规范版本:1.0  
    Java的虚拟机规范供应商:Sun Microsystems Inc.  
    Java的虚拟机规范名称:Java Virtual Machine Specification  
    Java的虚拟机实现版本:14.1-b02  
    Java的虚拟机实现供应商:Sun Microsystems Inc.  
    Java的虚拟机实现名称:Java HotSpot(TM) Client VM  
    Java运行时环境规范版本:1.6  
    Java运行时环境规范供应商:null  
    Java运行时环境规范名称:Java Platform API Specification  
    Java的类格式版本号:50.0  
    Java的类路径:C:/Java-Justin/DS;D:/Program Files/Eclipse/plugins/cpdetector/cpdetector.jar  
    加载库时搜索的路径列表:C:/Java/jre6/bin;.;C:/WINDOWS/Sun/Java/bin;C:/WINDOWS/system32;C:/WINDOWS;C:/Java/jre6/bin/client;C:/Java/jre6/bin;C:/WINDOWS/system32;C:/WINDOWS;C:/WINDOWS/System32/Wbem;C:/Program Files/ATI Technologies/ATI.ACE/Core-Static;D:/Program Files/Borland/SilkTest/  
    默认的临时文件路径:C:/DOCUME~1/JUSTIN~1/LOCALS~1/Temp/  
    一个或多个扩展目录的路径:C:/Java/jre6/lib/ext;C:/WINDOWS/Sun/Java/lib/ext  
    操作系统的名称:Windows XP  
    操作系统的构架:x86  
    操作系统的版本:5.1  
    文件分隔符:/  
    路径分隔符:;  
    行分隔符:  
    
    用户的账户名称:Justin & Avril  
    用户的主目录:C:/Documents and Settings/Justin & Avril  
    用户的当前工作目录:C:/Java-Justin/DS

     

  • CAS Server3.5.2 + Client3.2.1 单点登录(无证书全攻略)

    配置环境:
    JDK 1.6 + TOMCAT 6
    Yale CAS Server3.5.2 + Client3.2.1

    工作准备:
    到 http://www.jasig.org/cas 中下载对应版本的 服务器端cas-server-3.5.2-release.zip 和 客户端cas-client-3.2.1-release.zip

    一、尝试运行CAS服务器端
    解压cas-server-3.5.2-release.zip, 在里面的moudles文件夹里有个cas-server-webapp-3.5.2.war文件, 这个就是服务器的所有文件, 解压, 设置tomcat的server.xml把该文件夹添加对应的虚拟目录, 我们以 http://localhost:8080/cas 为例,登录 http://localhost:8080/cas 后你们可以看到登录界面,便于测试,CAS默认输入相同的账号跟密码即可通过登录验证。

    二、配置CAS服务端,使其读取mysql数据库对应的数据进行登录判断

    打开CAS的/WEB-INF/deployerConfigContext.xml,找到以下代码并注释掉,取消掉原来的用于测试的简单验证

    <bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />

    换成以下的验证方式

    <bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
    	<property name="dataSource" ref="dataSource" />
    	<property name="sql" value="SELECT password FROM account WHERE email=?" />
    </bean>

    并配置对应的数据源(添加bean):

    	<!-- 配置数据源 -->
    	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName">
    			<value>com.mysql.jdbc.Driver</value>
    		</property>
    		<property name="url">
    			<value>jdbc:mysql://localhost:3306/sway_account?useUnicode=true&amp;characterEncoding=utf-8</value>
    		</property>
    		<property name="username">
    			<value>root</value>
    		</property>
    		<property name="password">
    			<value></value>
    		</property>
    	</bean>

     

    三、配置CAS客户端

    新建一个tomcat虚拟目录,我们以 http://localhost:8080/test 为例,并且确保里面有一个可访问的文件(我们这里以index.jsp为例),解压cas-client-3.2.1-release.zip,在里面modules里面找到cas-client-core-3.2.1.jar以及commons-logging-1.1.jar文件,复制到 http://localhost:8080/test 项目里面的 WEB-INF/lib 文件夹里面,然后修改里面的web.xml文件,添加以下过滤器:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_ID" version="3.0"
    	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    
    	<welcome-file-list>
    		<welcome-file>index.jsp</welcome-file>  
    	</welcome-file-list>
    
    	<listener>
    		<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    	</listener>
    
    	<!--该过滤器用于实现单点登出功能,可选配置。 -->
    	<filter>
    		<filter-name>CAS Single Sign Out Filter</filter-name>
    		<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
    	</filter>
    	<filter-mapping>
    		<filter-name>CAS Single Sign Out Filter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    
    	<!--该过滤器负责用户的认证工作,必须启用它 -->
    	<filter>
    		<filter-name>CASFilter</filter-name>
    		<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
    		<init-param>
    			<param-name>casServerLoginUrl</param-name>
    			<param-value>http://localhost:8080/cas/login</param-value>
    			<!--这里的server是服务端的IP -->
    		</init-param>
    		<init-param>
    			<param-name>serverName</param-name>
    			<param-value>http://localhost:8080/</param-value>
    		</init-param>
    	</filter>
    	<filter-mapping>
    		<filter-name>CASFilter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    
    	<!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->
    	<!-- ValidationFilter 这个filter负责对请求参数ticket进行验证(ticket参数是负责子系统与CAS进行验证交互的凭证)casServerUrlPrefix:CAS服务访问地址serverName:当前应用所在的主机名 -->
    	<filter>
    		<filter-name>CAS Validation Filter</filter-name>
    		<filter-class>
    			org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
    		</filter-class>
    		<init-param>
    			<param-name>casServerUrlPrefix</param-name>
    			<param-value>http://localhost:8080/cas</param-value>
    		</init-param>
    		<init-param>
    			<param-name>serverName</param-name>
    			<param-value>http://localhost:8080/</param-value>
    		</init-param>
    	</filter>
    	<filter-mapping>
    		<filter-name>CAS Validation Filter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    
    	<!-- 3.(可选)HttpServletRequestWrapperFilter 这个是HttpServletRequet的包裹类,让他支持getUserPrincipal,getRemoteUser方法来取得用户信息 -->
    	<!-- 该过滤器负责实现HttpServletRequest请求的包裹,比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登 -->
    	<filter>
    		<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
    		<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
    	</filter>
    	<filter-mapping>
    		<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    
    	<!-- 4.(可选)AssertionThreadLocalFilter 这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息 Assertion assersion =AssertionHolder.getAssertion(); -->
    	<!--该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。比如AssertionHolder.getAssertion().getPrincipal().getName()。-->
    	<filter>
    		<filter-name>CAS Assertion Thread Local Filter</filter-name>
    		<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
    	</filter>
    	<filter-mapping>
    		<filter-name>CAS Assertion Thread Local Filter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    
    </web-app>

     

    四、读取更多的客户端信息

    打开CAS的/WEB-INF/deployerConfigContext.xml,
    找到bean id为attributeRepository的这个配置,修改为如下

    	
    	<bean id="attributeRepository" class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao">
    		<constructor-arg index="0" ref="dataSource" />
    		<constructor-arg index="1">
    			<value>select * from account where {0}</value>
    		</constructor-arg>
    		<!-- 组装sql用的查询条件属性 -->
    		<property name="queryAttributeMapping">
    			<map>
    				<entry key="username" value="email" />
    				<!-- <entry key="username" value="userAccount" /> -->
    			</map>
    		</property>
    		<!-- 如果要组装多个查询条件,需要加上下面这个,默认为AND -->
    		<!-- <property name="queryType">
    			<value>OR</value>
    		</property> -->
    		<!-- 要获取的属性在这里配置 -->
    		<property name="resultAttributeMapping">
    			<map>
    				<!--key为对应的数据库字段名称,value为提供给客户端获取的属性名字,系统会自动填充值 -->
    				<entry key="id" value="id" />
    				<entry key="email" value="email" />
    				<entry key="emailValidated" value="emailValidated" />
    				<entry key="password" value="password" />
    				<entry key="registerTime" value="registerTime" />
    				<entry key="lastLoginTime" value="lastLoginTime" />
    				<entry key="balance" value="balance" />
    			</map>
    		</property>
    	</bean>

    修改该xml文件中最后一个默认的serviceRegistryDao bean,找到<bean class=”org.jasig.cas.services.RegexRegisteredService”>把高亮部分添加进去:

    <bean class="org.jasig.cas.services.RegexRegisteredService">
                            <property name="id" value="0" />
                            <property name="name" value="HTTP and IMAP" />
                            <property name="description" value="Allows HTTP(S) and IMAP(S) protocols" />
                            <property name="serviceId" value="^(https?|imaps?)://.*" />
                            <property name="evaluationOrder" value="10000001" />
                            <property name="ignoreAttributes" value="true"/>
                        </bean>

    最后修改WEB-INF\view\jsp\protocol\2.0\casServiceValidationSuccess.jsp文件

    <%@page pageEncoding="UTF-8"%>
    <%@ page session="false" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
    
    <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
    
    	<cas:authenticationSuccess>
            <cas:user>${fn:escapeXml(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.id)}</cas:user>                
            <c:if test="${not empty pgtIou}">
                    <cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket>
            </c:if>
            <c:if test="${fn:length(assertion.chainedAuthentications) > 1}">
                    <cas:proxies>
                    <c:forEach var="proxy" items="${assertion.chainedAuthentications}" varStatus="loopStatus" begin="0" end="${fn:length(assertion.chainedAuthentications)-2}" step="1">
                                <cas:proxy>${fn:escapeXml(proxy.principal.id)}</cas:proxy>
                    </c:forEach>
                    </cas:proxies>
            </c:if>
            <!-- 在server验证成功后,这个页面负责生成与客户端交互的xml信息,在默认的casServiceValidationSuccess.jsp中,只包括用户名,并不提供其他的属性信息,因此需要对页面进行扩展 -->
            <c:if test="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes) > 0}">   
                <cas:attributes>   
                    <c:forEach var="attr" items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}">                             
                        <cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}>                                 
                    </c:forEach>     
                </cas:attributes>   
            </c:if> 
        </cas:authenticationSuccess>
    
    </cas:serviceResponse>

    然后即可使用以下代码在index.jsp中获取对应的返回对象:

    AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
    Map<String, Object> attributes = principal.getAttributes();

    以下是我用于测试的index.jsp

    <%@ page language="java" import="java.util.*" contentType="text/html;charset=utf-8"%>
    <%@ page import="org.jasig.cas.client.authentication.AttributePrincipal,org.jasig.cas.client.validation.Assertion,org.jasig.cas.client.util.AbstractCasFilter"%>
    
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    	<base href="<%=basePath%>">
    	<title>CAS单点登录VS退出</title>
    </head>
    <body>
    
    <%
    AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
    Map<String, Object> attributes = principal.getAttributes();
    /*for(Map.Entry<String,Object> m: attributes.entrySet()){ 
    	System.out.println(m.getKey()+"---"+m.getValue()); 
    }*/
    %>
    
    [ 单点登录测试 ]<br /><br />
    用户名:<%=principal.getName()%><br />
    id:<%=attributes.get("id")%><br />
    email:<%=attributes.get("email")%><br />
    emailValidated:<%=attributes.get("emailValidated")%><br />
    password:<%=attributes.get("password")%><br />
    registerTime:<%=attributes.get("registerTime")%><br />
    lastLoginTime:<%=attributes.get("lastLoginTime")%><br />
    balance:<%=attributes.get("balance")%><br />
    <br />
    <a href="http://localhost:8080/sway/cas/logout">退出</a><br /><br />
    <hr/>
    <br /><br />
    [ DEBUG ]<br /><br />
    map中元素个数为<%=attributes.size()%>
    
    </body>
    
    </html>

    至此配置完毕,往后再教大家配置对应的SSL加密。