需求:在cxf+spring环境下,针对某个接口,限制Ip地址对其访问次数,超过一定访问次数后抛出异常。
1.此Ip地址是经过拦截器被允许访问的;
2.同一IP地址对接口的访问次数不能超过两次。
备注:有关web.xml,服务器端、客户端配置文件,数据库工具类,简单输出示例,请参考前面写过的cxf+spring开发(一)和cxf+spring开发(二)
一、自定义超过最大访问次数异常
/**
* 自定义超出最大访问限制异常
*
*/
public class OutOfAccNumException extends Exception{
public OutOfAccNumException(String msg) {
super(msg);
}
}
二、连接池处理
operatelock方法的参数有两个,第一个可传入Ip地址,第二个是操作类型,进入接口中方法就加一,方法执行结束就减一。定义一个hashmap变量统计同一Ip地址的访问次数,超过最大限制就抛出自定义异常。
import java.util.HashMap;
import java.util.Map;
/**
* 连接池处理
*
*/
public class ALock {
public static String COUNT_TYPE_ADD = "COUNT_ADD";//访问数加一
public static String COUNT_TYPE_SUB = "COUNT_SUB";//访问数减一
private static int maxNum = 2;//最大允许访问数
private static Map<String, Integer> cateCount = new HashMap<String, Integer>();
/**
* 线程处理
* @param cateAcc
* 访问名
* @param countType
* OPT_ADD/OPT_SUB
* @throws OutOfAccNumException
* 访问次数超过限制
*/
public static synchronized void operatelock(String cateAcc, String countType)
throws OutOfAccNumException{
int currentCount = 0;
if (cateCount.get(cateAcc) != null) {
// System.out.println(cateCount.get(cateAcc));
currentCount = Integer.parseInt(cateCount.get(cateAcc).toString());
// System.out.println("执行map.get操作:当前访问数:" + currentCount);
// System.out.println(Integer.parseInt(cateAcc));
// System.out.println(Integer.parseInt("9"));
}
if (COUNT_TYPE_ADD.equals(countType)) {
if (currentCount >= maxNum) {
System.out.println("已达最大访问数:" + currentCount);
System.out.println(Thread.currentThread().getName());
cateCount.put(cateAcc, Integer.valueOf(++currentCount));
throw new OutOfAccNumException("已达最大访问数," + Thread.currentThread().getName()
+ "拒绝继续访问");
}else {
currentCount++;
System.out.println("执行add操作:当前访问数:" + currentCount);
cateCount.put(cateAcc, Integer.valueOf(currentCount));
}
}else if (COUNT_TYPE_SUB.equals(countType)) {
currentCount--;
System.out.println("执行sub操作:当前访问数:" + currentCount);
cateCount.put(cateAcc, Integer.valueOf(currentCount));
}
}
}
二、获取Ip地址
此处不同于上一篇博文Ip拦截器中的Ip获取方式,直接获取客户端请求的Ip地址,方便后续的传参。
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import org.apache.cxf.jaxws.context.WebServiceContextImpl;
/**
* 获取Ip地址
*
*/
public class GetIpAddr {
public static String getWSRemoteIP()
{
WebServiceContext wscontext = new WebServiceContextImpl();
MessageContext mc = wscontext.getMessageContext();
HttpServletRequest request = (HttpServletRequest)(mc.get(MessageContext.SERVLET_REQUEST));
String remortAddress = request.getRemoteAddr();
if("127.0.0.1".equals(remortAddress)) {
try {
remortAddress = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
return "";
}
}
return remortAddress;
}
}
三、定义限制访问次数的抽象类
/**
* 定义抽象类
*
*/
public abstract class UseOperFactory {
// private String accName;
public static String COUNT_TYPE_ADD = "COUNT_ADD";//访问数加一
public static String COUNT_TYPE_SUB = "COUNT_SUB";//访问数减一
private String s;
public UseOperFactory(String string) {
this.s = string;
}
public void useLock() {
try {
System.out.println("现在正在访问的Ip是:"+ GetIpAddr.getWSRemoteIP());
ALock.operatelock(GetIpAddr.getWSRemoteIP(), COUNT_TYPE_ADD);
// System.out.println("Hello," + s);
doWork();
Thread.sleep(1000*10);
} catch (OutOfAccNumException e1) {
System.err.println(e1.getMessage());
e1.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
//释放资源
try {
ALock.operatelock(GetIpAddr.getWSRemoteIP(), COUNT_TYPE_SUB);
} catch (OutOfAccNumException e) {
e.printStackTrace();
}
}
}
public abstract void doWork();
}
四、修改接口实现类(接口见cxf+spring开发(一))
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import javax.jws.WebService;
/**
* 实现接口
*/
@WebService(endpointInterface = "com.yolanda.cxfTest.AInterface")
public class AImpl implements AInterface {
public static String COUNT_TYPE_ADD = "COUNT_ADD";//访问数加一
public static String COUNT_TYPE_SUB = "COUNT_SUB";//访问数减一
public void print(String s) {
UseOperFactory uof = new UseOperFactory(s) {
public void doWork() {
System.out.println("Hello," + s);
}
};
uof.useLock();
}
public String printAll(List<AEntity> aEntities) {
String aString = "list:\n";
for (AEntity aEntity : aEntities) {
aString += "name:" + aEntity.getName() + "," + "age:"
+ aEntity.getAge() + "\n";
// count.decrementAndGet();
}
return aString;
}
}
五、客户端测试文件
创建固定线程数量的线程池进行测试。
import java.util.List;
import javax.jws.WebService;
/**
* 实现接口
*/
@WebService(endpointInterface = "com.yolanda.cxfTest.AInterface")
public class AImpl implements AInterface {
public static String COUNT_TYPE_ADD = "COUNT_ADD";//访问数加一
public static String COUNT_TYPE_SUB = "COUNT_SUB";//访问数减一
public void print(String s) {
UseOperFactory uof = new UseOperFactory(s) {
public void doWork() {
System.out.println("Hello," + s);
}
};
uof.useLock();
}
public String printAll(List<AEntity> aEntities) {
String aString = "list:\n";
for (AEntity aEntity : aEntities) {
aString += "name:" + aEntity.getName() + "," + "age:"
+ aEntity.getAge() + "\n";
// count.decrementAndGet();
}
return aString;
}
}