文章目录

平常心博客

平常心的日常积累

存档: 2017 年 11 月 (19)

【原创】jcaptcha和kaptcha验证码使用入门

这篇是从老博客中迁移过来的,时间有点久远

一、 jcaptcha验证码使用

jcaptcha使用默认样式生成的验证码比较难以识别,所以需要自定义验证码的样式,包括,背景色、背景大小、字体、字体大小、生成的字符数等。相对与kaptcha比较复杂。

1.1、 纯代码实现jcaptcha验证码

1. 首先创建一个javaWeb工程添加jcaptcha包和它所依赖的包,添加完成后:

cd8db7e77d1949edb44cee38d9308628-image.png

【转载】标准Web系统的架构分层

标准Web系统的架构分层

1、架构体系分层图

e5ed16bc85ac4e9e9f7a5bfc723a4790-20150613151236032.png

在上图中我们描述了Web系统架构中的组成部分。并且给出了每一层常用的技术组件/服务实现。需要注意以下几点:

  • 系统架构是灵活的,根据需求的不同,不一定每一层的技术都需要使用。例如:一些简单的CRM系统可能在产品初期并不需要K-V作为缓存;一些系统访问量不大,并且可能只有一台业务服务器存在,所以不需要运用负载均衡层。

  • 业务系统间通信层并没有加入传统的HTTP请求方式。这是因为HTTP请求-响应的延迟比较高,并且有很多次和正式请求无关的通信(这在下面的内容中会详细讲到)。所以,传统的HTTP请求方式并不适合在两个高负载系统之间使用,其更多的应用场景是各种客户端(WEB、IOS、Android等)->服务器端的请求调用。

  • 我们把业务编码中常使用的缓存系统归入到数据存储层,是因为类似于Redis这样的K-V存储系统,从本质上讲是一种键值数据库。为什么Redis会很快以至于可以作为缓存使用,我将在随后的文章中进行详细的描述。

  • 还有一点需要注意的是,上面架构图中的每层之间实际上不存在绝对的联系(例如负载层一定会把请求转送的业务层,这样的必然性是不存在的),在通常情况下各层是可以跨越访问的。举例说明:如果HTTP访问的是一张图片资源,负载层不会把请求送到业务层,而是直接到部署的分布式文件系统上寻找图片资源并返回。再比如运用LVS做Mysql负载时,负载层是直接和数据存储层进行合作。

【转载】Spring/Boot/Cloud系列知识(7)——Spring Aspectj EL(3) 有更新!

(接上文《Spring/Boot/Cloud系列知识(6)——Spring EL(2)》)

3.3、Spring EL 与 AOP(Aspectj)

3.3.1、Spring 和 AOP的关系

AOP是面向切面编程的简称,Spring的设计思路受到这个思想的指导。所以我们在使用Spring各种组件的时候都能看到这个设计思路的影子。
2f4cdb3be2f842b0ac5612d8822ee96a-20171104181037554.png
再举一些实际的例子:我们使用Spring托管hibernate就是一个典型的AOP例子,事务的开启、提交、回滚操作无需业务开发人员进行,全部在业务方法之外自动完成;Spring Cache组件的使用也是一个典型的AOP实例,完成Spring Cache EL的配置后,对Redis/Memcache或者Google Cache的操作完全不需要书写额外代码,全部在业务方法以外完成;而我们之前介绍的Spring中使用的两种代理模式,也是基于AOP思想,无论是JAVA原生动态代理还是Cglib动态代理,都无需业务开发者书写一行额外代码即可完成代理过程。由此可见AOP思想在Spring中的体现是深入的、延续的且广泛的。

【转载】Spring/Boot/Cloud系列知识(6)——Spring EL(2) 有更新!

接上文《Spring/Boot/Cloud系列知识(5)——Spring EL(1)》)

3、Spring EL 与第三方信息

3.1、Spring EL 与 集合

Spring EL基本表达式可以对集合中的信息进行读取操作,包括Collection、Map性质的集合。请看如下实例:

/**
 * 在这个bean被初始化时,进行集合数据的添加
 * @author yinwenjie
 */
@Component("myCollection")
public class CollectionPojo {
  private List<String> myList;
  private Map<String, Object> myMap;
  /**
   * 保证spring在构造这个bean实例时
   * 就向两个集合中写入了数据
   */
  public CollectionPojo() {
    this.myList = Arrays.asList(new String[]{"数据1","数据2","数据3","数据4"});
    this.myMap = new HashMap<>();
    myMap.put("key1", "value1");
    myMap.put("key2", "value2");
    myMap.put("key3", "value3");
  }
  ......
}

【转载】Web系统大规模并发——电商秒杀与抢购

电商的秒杀和抢购,对我们来说,都不是一个陌生的东西。然而,从技术的角度来说,这对于Web系统是一个巨大的考验。当一个Web系统,在一秒钟内收到数以 万计甚至更多请求时,系统的优化和稳定至关重要。这次我们会关注秒杀和抢购的技术实现和优化,同时,从技术层面揭开,为什么我们总是不容易抢到火车票的原 因?

一、大规模并发带来的挑战

在过去的工作中,我曾经面对过5w每秒的高并发秒杀功能,在这个过程中,整个Web系统遇到了很多的问题和挑战。如果Web系统不做针对性的优化,会轻而易举地陷入到异常状态。我们现在一起来讨论下,优化的思路和方法哈。

1. 请求接口的合理设计

一个秒杀或者抢购页面,通常分为2个部分,一个是静态的HTML等内容,另一个就是参与秒杀的Web后台请求接口。

【转载】Spring/Boot/Cloud系列知识(5)——Spring EL(1) 有更新!

1、Spring EL 概述

Spring EL是Spring Expression Language的简称,中文称作Spring表达式语言。Spring EL并不单单指代某一种特定的表达式格式,而是对Spring中字符串表达式的一个概要性称呼。Spring EL基本功能由Spring核心包提供支持(spring-core组件和spring-context组件),并且不同的组件还对Spring EL的基本功能提供扩展。本文(及后续一文)主要对读者会在实际工作中使用到的Spring EL 进行讲述,并在最后结合一个使用Spring EL 完成自定义注解实例。

2、Spring EL 基本使用

Spring EL 的使用非常灵活,并且主要由“@Value”注解标记进行支撑。“@Value”注解可以在属性、方法上使用,通过这个注解可以基于IOC容器中的bean对象、对象属性、对象方法、操作符计算结果、正则表达式匹配结果、应用程序配置结果、操作系统环境变量配置结果等等,对目标属性、方法入参进行赋值

【转载】Spring/Boot/Cloud系列知识(4)——代理模式(下) 有更新!

接上文《Spring/Boot/Cloud系列知识(3)——代理模式(中)》)

3.3 Proxy.newProxyInstance内部如何完成工作的

我们来看看org.mockito.cglib.proxy.Proxy.newProxyInstance这个方法内部的代码:

public class Proxy implements Serializable {
    ......

    // 这个常量BADOBJECTMETHOD_FILTER(代理选择器)的设定,等一下会用到
    // 实际上代码也清楚,一般情况下执行第0个代理器,如果是代理执行java.lang.Object中的方法
    // 且这些方法又不是hashCode()、equals()、toString(),则执行第1个代理器
    private static final CallbackFilter BADOBJECTMETHOD_FILTER = new CallbackFilter() {
        public int accept(Method method) {
            if (method.getDeclaringClass().getName().equals("java.lang.Object")) {
                String name = method.getName();
                if (!(name.equals("hashCode") ||
                      name.equals("equals") ||
                      name.equals("toString"))) {
                    return 1;
                }
            }
            return 0;
        }
    };

    ......

    // private for security of isProxyClass
    private static class ProxyImpl extends Proxy {
        protected ProxyImpl(InvocationHandler h) {
            super(h);
        }
    }

    ......

    // 该方法中使用了Cglib中对ASM freamework的封装,动态创建一个class定义
    public static Class getProxyClass(ClassLoader loader, Class[] interfaces) {
        Enhancer e = new Enhancer();
        // 为这个class设置一个父类,这个父类名叫ProxyImpl,其中定义了一个构造函数
        // 那个构造函数需要传入个代理器对象
        e.setSuperclass(ProxyImpl.class);
        // 然后为这个class设置接口,请注意,可以设置多个接口哦
        e.setInterfaces(interfaces);
        // 为这个动态class设置代理器类型,设定了这个方法就应该使用CallbackFilter设定代理选择器(过滤器)
        e.setCallbackTypes(new Class[]{
            InvocationHandler.class,
            NoOp.class,
        });
        // 这个我们使用了Proxy中,在前文定义好的BADOBJECTMETHOD_FILTER常量,请参见
        //  
        e.setCallbackFilter(BADOBJECTMETHOD_FILTER);
        e.setUseFactory(false);
        // 最后创建这个动态class(注意是创建class,并不是这个class的实例)
        return e.createClass();
    }

    ......

    // newProxyInstance方法中实际上就是两句话,重要的代码都在getProxyClass这个方法中。
    public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) {
        try {
            // 该方法用来动态创建一个class,请参考方法中的内容
            Class clazz = getProxyClass(loader, interfaces);
            // 很显然,通过以上方法我们拿到了一个动态class,这个class有三个重要特点,
            // 1、这个class有一个带有参数的构造函数,这个参数就是需要我们传入代理器接口的一个实现实例。
            // 2、这个class实现了我们需要它实现的一个或者多个接口——没有实现代码,但是有这样的类结构
            // 3、这个class设定了两个代理器,通常执行第0个代理器,就是我们传入的InvocationHandler h对象
            // 另外,如果是代理执行java.lang.Object中的方法
            // 且这些方法又不是hashCode()、equals()、toString(),则执行第1个代理器
            //
            // 接着,我们执行第二句代码,这句代码初始化一个这个动态类的示例,并传入代理器实例对象
            return clazz.getConstructor(new Class[]{ InvocationHandler.class }).newInstance(new Object[]{ h });
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new CodeGenerationException(e);
        }
    }

    ......
}

要阅读本小节以上代码片段,请从上篇文章中newProxyInstance()方法开始看。

【转载】Spring/Boot/Cloud系列知识(3)——代理模式(中) 有更新!

接上文《Spring/Boot/Cloud系列知识(2)——代理模式(上)》)

2.2、代理模式在Spring中的应用

那么java中基于java.lang.reflect.Proxy的动态代理模式和Spring生态有什么关系呢?Spring中的所有Bean实例存储在一个名叫IOC容器(Inversion of Control 控制反转容器)中。这个容器中存在着接口和实现类的对应关系(也可以直接存储类的实例,无需这个类有任何接口的实现),而其中Bean实例的存储方式都默认采用单例保存。

一般情况下我们可以通过BeanFactory(Spring IOC容器工厂)接口中getBean()方法,直接获取到这个接口在IOC容器中对应的实例。但当我们需要为这个Bean实例附加AOP切面操作时,这个实例就会被代理——视这个实例实现接口的情况和Spring的配置情况,又可以区别为使用Proxy动态代理还是使用Cglib代理。如下图所示:

【转载】Spring/Boot/Cloud系列知识(2)——代理模式(上) 有更新!

代理模式是23种设计模式中的一种,属于一种结构模式。用一句大白话解释这个设计模式:当外部调用者调用A来完成一件事情/一个动作时,并不直接调用A本身,而是调用一个代理者,并再由代理者负责调用真实的执行者A,最终达到间接调用的目的。

代理模式(动态)和Cglib代理是Spring生态中的最基础设计原理之一,所以要了解Spring的工作原理就必须先讨论清楚代理模式的设计思路(无论是静态代理还是动态代理)。

1. 代理模式(静态)

5990d0eccc734dcca2dbb043443692fa-20170906204228195.png
(代理模式——静态)

上图显示了一个标准的代理模式(静态)类关系结构。在标准的代理模式(静态)中,至少存在以下角色:

  • Subject接口或抽象角色:对于外部调用者来说只关心调用操作是否被执行,而不会关心本次调用是被直接执行的还是被代理者间接执行的。所以一般来说代理执行者会实现和被代理者相同的接口(或抽象类),“伪装”成被代理的对象(上图中就是伪装成RealSubject类)。

  • RealSubject:被代理的真实业务执行者。简单来说就是真实业务由这个角色负责执行,只是为了在业务处理前后能够执行其它操作,所以真实业务执行者才会被代理(上图中就是被Proxy代理)。

  • Proxy:代理执行者。代理执行者内部引用了真实执行者,并根据需要在真实业务执行前后,执行其它操作:例如判断入参是否符合要求、打开数据库连接、捕获异常发送到事件搜集器中……

以下的代码片段说明了代理模式(静态)中以上几个工作角色的简单实现:

【转载】Spring/Boot/Cloud系列知识(1)——开篇 有更新!

1. 开篇序

各位支持我的朋友大家好啊,博客停了两个月处理了一些私人事务。从今天开始本人恢复技术博客更新。欢迎大家继续关注

1.1 写作难度在哪里

Spring系列知识这个博文专题实际上很早之前就想写写,但是一直没有动笔或者说没敢动笔。究其原因主要有几个:

1、这个系列的博文专题并不好写,Spring Framework知识体系太过庞大,远远超过本人之前所写的线程专题、系统间通讯专题、负载均衡专题和系统存储专题。Spring生态从很早的2.X版本到3.X版本再到当前的4.X版本、从最初的XML配置到注解性配置,再到现在最流行的Java Style配置、从单纯的Spring Framework到Spring Boot,再到目前流行的Spring Cloud服务治理生态……我一个小小的IT屌丝哪里能全部掌握……

【转载】SpringCloud(一) 服务的注册与发现(Eureka) 有更新!

SpringCloud 服务的注册与发现(Eureka)

Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中涉及的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。

Spring Cloud简介

Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config、Spring Cloud Netflix、Spring Cloud0 CloudFoundry、Spring Cloud AWS、Spring Cloud Security、Spring Cloud Commons、Spring Cloud Zookeeper、Spring Cloud CLI等项目。

【转载】启动tomcat时,一直卡在Deploying web application directory这块的解决方案 有更新!

1、现象

Tomcat在启动时一直卡在Deploying web application directory这句日志上,日志如下:

[root@iz8vbdzx7y7owm488t4d89z bin]# tail -f ../logs/catalina.out
09-Jun-2017 15:57:06.666 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["ajp-nio-8009"]
09-Jun-2017 15:57:06.667 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
09-Jun-2017 15:57:06.667 INFO [main] org.apache.catalina.startup.Catalina.load Initialization processed in 535 ms
09-Jun-2017 15:57:06.684 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service Catalina
09-Jun-2017 15:57:06.684 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.0.15
09-Jun-2017 15:57:06.690 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /opt/apache-tomcat-8.0.15-server/webapps/ROOT

【转载】Centos 7 使用Yum 安装 MySQL 有更新!

1、介绍

centos 从7 开始将原先自带的MySQL被更替为mariadb,默认情况下推荐安装mariadb或Percona,如果对于原版有比较深的情节,可以按照如下方式进行安装。

2、安装YUM Repo

Repo地址可从官方获取:https://dev.mysql.com/downloads/repo/yum/
5066d619c9a54eb086fd72ae891325e1-mysql.png
这里选择的是 Red Hat Enterprise Linux 7 / Oracle Linux 7 (Architecture Independent), RPM Package(原因是CentOS就是RedHat重新编译的版本)。下载地址可以点击链接查看,或自己按照规则拼接:
wget https://dev.mysql.com/get/mysql57-community-release-el7-9.noarch.rpm
完成后可以检测下md5是否与页面上的一致:
md5sum mysql57-community-release-el7-9.noarch.rpm
然后进行repo的安装:
rpm -ivh mysql57-community-release-el7-9.noarch.rpm

Linux下安装elasticsearch报找不到java

centos7.2下安装elasticsearch5.x你的java环境是没有问题的但是在启动是就会报:

which: no java in (/sbin:/bin:/usr/sbin:/usr/bin)
Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME

简单解决方案是:

  1. vi /etc/sysconfig/elasticsearch
  2. 将 JAVAHOME=/root/jdk1.8.060 写到文件中保存后启动
  3. service elasticsearch start
    正在启动 elasticsearch: [确定]

这样就能解决找不到java环境的问题了。

【转载】解决Linux操作系统下AES解密失败的问题

现象描述:

windows上加解密正常,linux上加密正常,解密时发生如下异常:

javax.crypto.BadPaddingException: Given final block not properly padded

       at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
       at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
       at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
       at javax.crypto.Cipher.doFinal(DashoA13*..)
       at chb.test.crypto.AESUtils.crypt(AESUtils.java:386)
       at chb.test.crypto.AESUtils.AesDecrypt(AESUtils.java:254)
       at chb.test.crypto.AESUtils.main(AESUtils.java:40)

解决方法:

经过检查之后,定位在生成KEY的方法上,如下:

public static SecretKey getKey (String strKey) {  
	try {           
		KeyGenerator _generator = KeyGenerator.getInstance( "AES" );  
		_generator.init(128, new SecureRandom(strKey.getBytes()));  
			return _generator.generateKey();  
	}  catch (Exception e) {  
		 throw new RuntimeException( " 初始化密钥出现异常 " );  
	}  
} 

http client调用API接口发生Stream closed错误

java中使用httpcomponents调用远程的API接口时发生Stream closed错误:

2015/08/07 13:03:12,887 ERROR [stderr] (Thread-101) java.io.IOException: Stream closed
2015/08/07 13:03:12,887 ERROR [stderr] (Thread-101)     at java.util.zip.GZIPInputStream.ensureOpen(GZIPInputStream.java:61)
2015/08/07 13:03:12,887 ERROR [stderr] (Thread-101)     at java.util.zip.GZIPInputStream.read(GZIPInputStream.java:112)
2015/08/07 13:03:12,887 ERROR [stderr] (Thread-101)     at org.apache.http.client.entity.LazyDecompressingInputStream.read(LazyDecompressingInputStream.java:74)
2015/08/07 13:03:12,887 ERROR [stderr] (Thread-101)     at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
2015/08/07 13:03:12,887 ERROR [stderr] (Thread-101)     at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
2015/08/07 13:03:12,887 ERROR [stderr] (Thread-101)     at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
2015/08/07 13:03:12,887 ERROR [stderr] (Thread-101)     at java.io.InputStreamReader.read(InputStreamReader.java:184)
2015/08/07 13:03:12,888 ERROR [stderr] (Thread-101)     at java.io.Reader.read(Reader.java:140)
2015/08/07 13:03:12,888 ERROR [stderr] (Thread-101)     at org.apache.http.util.EntityUtils.toString(EntityUtils.java:244)
2015/08/07 13:03:12,888 ERROR [stderr] (Thread-101)     at org.apache.http.util.EntityUtils.toString(EntityUtils.java:288)
2015/08/07 13:03:12,888 ERROR [stderr] (Thread-101)     at mainThread.Search.doRequest(Search.java:70)
2015/08/07 13:03:12,888 ERROR [stderr] (Thread-101)     at mainThread.Search.search(Search.java:29)

经过查找在Stack Overflow中找到了答案。

【转载】解决 - java.lang.OutOfMemoryError: unable to create new native thread

一、概述

工作中碰到过这个问题好几次了,觉得有必要总结一下,所以有了这篇文章,这篇文章分为三个部分:认识问题、分析问题、解决问题。

二、认识问题:

首先我们通过下面这个 测试程序 来认识这个问题:
运行的环境 (有必要说明一下,不同环境会有不同的结果):32位 Windows XP,Sun JDK 1.6.0_18, eclipse 3.4,
测试程序:

import java.util.concurrent.CountDownLatch;

public class TestNativeOutOfMemoryError {

	public static void main(String[] args) {

		for (int i = 0;; i++) {
			System.out.println("i = " + i);
			new Thread(new HoldThread()).start();
		}
	}
}

class HoldThread extends Thread {
	CountDownLatch cdl = new CountDownLatch(1);

	public HoldThread() {
		this.setDaemon(true);
	}

	public void run() {
		try {
			cdl.await();
		} catch (InterruptedException e) {
		}
	}
}

【转载】MySql+Mybatis+Druid在一个Mybatis中执行多条SQL 有更新!

做一个批量update的操作 ,sqlmap如下:

<update id="updateBatch" parameterType="java.util.List">  
  <foreach collection="list" item="item" index="index" open="" close="" separator=";">  
    update devicebdtoken   
	 <set>  
	   access_token=#{item.accessToken}  
	 <set>  
    where device_id = #{item.deviceId}  
  <foreach>  
<update>

在不设置的情况下会报错:

Caused by: java.sql.SQLException: sql injection violation, multi-statement not allow : update device_bd_token 
                 SET access_token=? 
                where device_id = ?
          ; 
                update device_bd_token 
                 SET access_token=? 
                where device_id = ?
	at com.alibaba.druid.wall.WallFilter.check(WallFilter.java:714)
	at com.alibaba.druid.wall.WallFilter.connection_prepareStatement(WallFilter.java:240)
	at com.alibaba.druid.filter.FilterChainImpl.connection_prepareStatement(FilterChainImpl.java:448)
	at com.alibaba.druid.filter.FilterAdapter.connection_prepareStatement(FilterAdapter.java:928)
	at com.alibaba.druid.filter.FilterEventAdapter.connection_prepareStatement(FilterEventAdapter.java:122)
	at com.alibaba.druid.filter.FilterChainImpl.connection_prepareStatement(FilterChainImpl.java:448)
	at com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl.prepareStatement(ConnectionProxyImpl.java:342)
	at com.alibaba.druid.pool.DruidPooledConnection.prepareStatement(DruidPooledConnection.java:318)

刚开始以为是连接数据库的url上没有加上支持批量的参数,然后就改了下:

jdbc.url=jdbc:mysql://192.168.11.107:3306/alarm_db?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8

结果还是同样的错误!但是在命令行直接执行又是没问题的,这就很奇怪了!

浏览次数:1633812   文章总数:80   评论总数:6   当前访客:3
平常心博客 © 2018 ×
¥
每天领支付宝红包
Powered by B3log 开源Solo 2.4.0