Mybatis返回Map类型数据

一、需求

在开发中,我们有时候需要将结果集映射成Map类型,不是List<Map>,如下:

 

sql查询得到的结果是:

sql_result

而我们需要的数据格式是:

Jietu20171227-201458

对应bean的属性类型为:

Jietu20171227-202747

二、解决方案:

1、在service层实现

这种方法会让service层显得比较臃肿,如果系统中用的比较多,会重复写很多这样的代码

2、编写mybatis拦截器实现

根据多种尝试,最终决定写mybatis拦截器进行实现。

2.1、先写一个拦截器


package com.renyiwei.mybatis.interceptor;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;

@Intercepts({ @Signature(method = "handleResultSets", type = ResultSetHandler.class, args = { Statement.class }) })
public class MapInterceptor implements Interceptor {

@SuppressWarnings("unused")
private Properties properties;

@Override
public Object intercept(Invocation invocation) throws Throwable {
ResultSetHandler resultSetHandler = (ResultSetHandler) invocation.getTarget();
Class clazz = resultSetHandler.getClass();
// 反射读取boundSql 获得sql语句
Field field = clazz.getDeclaredField("boundSql");
field.setAccessible(true);
BoundSql boundsql = (BoundSql) field.get(resultSetHandler);
String sql = boundsql.getSql();
// 如果sql中包含 MAP_KEY 和 MAP_VALUE 则被认为需要该将结果集转为Map类型
if (sql.contains("MAP_KEY") && sql.contains("MAP_VALUE")) {
try {
List> list = new ArrayList>();
Map map = new HashMap();
Statement statement = (Statement) invocation.getArgs()[0]; // 取得方法的参数Statement
ResultSet rs = statement.getResultSet(); // 取得结果集
while (rs.next()) {
String mapKey = rs.getString("MAP_KEY");
Object mapValue = rs.getObject("MAP_VALUE");
map.put(mapKey, mapValue); // 取得结果集后K、V关联后放到MAP当中
}
list.add(map);
// 这里返回list,而不是直接返回map
return list;
} catch (Exception e) {
// 如果出现异常,可能是冲突,则...
return invocation.proceed();
}

}
// 如果没有进行拦截处理,则执行默认逻辑
return invocation.proceed();
}

@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}

@Override
public void setProperties(Properties properties) {
this.properties = properties;
}

}

2.2、配置拦截器




2.3、写sql语句



JSTL JavaScript 冲突 HTTP Status 500 – Unable to compile class for JSP

以前也碰到过这样的问题,有些js写在jsp视图中,就报错,那时候没有找到原因,就直接把js放到外部文件中进行引用了。这次花了点时间去琢磨了一下。

首先申明:我这个解决方案并不适用所有出现该问题的,这只是导致该问题出现的一种原因,所以如果不适合你,请勿怪,非常感谢。

具体的报错如下:

HTTP Status 500  Unable to compile class for JSP

type Exception report

message Unable to compile class for JSP

description The server encountered an internal error that prevented it from fulfilling this request.

exception

org.apache.jasper.JasperException: Unable to compile class for JSP
org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:677)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:364)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:395)

	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:339)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:209)
	org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:267)
	org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1221)
	org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
	org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)
	org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
	org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	com.renyiwei.web.filter.XssFilter.doFilter(XssFilter.java:27)
	org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
	org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
	org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
	org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
	org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
	org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
root cause

java.lang.ArrayIndexOutOfBoundsException
java.lang.System.arraycopy(Native Method)
org.gjt.xpp.impl.tokenizer.Tokenizer.next(Tokenizer.java:1274)
org.gjt.xpp.impl.pullparser.PullParser.next(PullParser.java:392)
org.gjt.xpp.sax2.Driver.parseSubTree(Driver.java:415)
org.gjt.xpp.sax2.Driver.parse(Driver.java:310)
javax.xml.parsers.SAXParser.parse(SAXParser.java:392)
javax.xml.parsers.SAXParser.parse(SAXParser.java:195)
org.apache.taglibs.standard.tlv.JstlBaseTLV.validate(JstlBaseTLV.java:194)
org.apache.taglibs.standard.tlv.JstlFmtTLV.validate(JstlFmtTLV.java:134)
org.apache.jasper.compiler.TagLibraryInfoImpl.validate(TagLibraryInfoImpl.java:776)
org.apache.jasper.compiler.Validator.validateXmlView(Validator.java:1882)
org.apache.jasper.compiler.Validator.validateExDirectives(Validator.java:1851)
org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:218)
org.apache.jasper.compiler.Compiler.compile(Compiler.java:374)
org.apache.jasper.compiler.Compiler.compile(Compiler.java:354)
org.apache.jasper.compiler.Compiler.compile(Compiler.java:341)
org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:662)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:364)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:395)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:339)
javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:209)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:267)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1221)

	org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
	org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)
	org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
	org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	com.renyiwei.web.filter.XssFilter.doFilter(XssFilter.java:27)
	org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
	org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
	org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
	org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
	org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
	org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
	org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
	org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
	org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.70 logs.

Apache Tomcat/7.0.70

HTTP_Status_500_Unable_to_compile_class_for_JSP

Debug过程:

Google了很久,网上说jstl包的缘故,我也进行更换,发现没有解决问题。然后把jsp单独拿出来放一个空项目中跑,是可以的。在空项目中把所有的包放进去,会出现问题,确定是导入的包的问题。根据报错日志和对包的排查,最后发现去掉pull-parser-2.jar这个jar包之后,页面显示就正常了。

解决方案:

这个pull-parser-2.jar是被dom4j依赖的,所以我更换了该包的版本,问题得到解决。

<dependency>
 <groupId>pull−parser</groupId>
 <artifactId>pull−parser</artifactId>
 <version>2.1.10</version>
 </dependency>

 <dependency>
 <groupId>org.dom4j</groupId>
 <artifactId>dom4j</artifactId>
 <version>2.0.0−RC1</version>
 </dependency>

ueditor整合springmvc

ueditor自带jsp后端处理,但不是很灵活。比如我需要不同的功能模块上传的路径不同,或者需要做权限控制,就需要重新整合。下面是我的整合方案,供参考,没有此类需求的请不要喷!

1、在控制器中定义一个方法接收ueditor的请求:

2、自定义MpActionEnter继承自身的ActionEnter:

3、通过属性解析器将MpActionEnter注入到控制器的方法中:

4、在配置文件中添加属性解析器:

5、在前端页面重新定义serverUrl:

SpringMVC自定义方法参数解析器 绑定mybatis分页PageBounds类型参数

一、需求 

mybatis整合了分页插件mybatis-paginator之后,我们需要从构造一个PageBounds类传入Mapper完成分页,构造PageBounds需要一些参数,比如当前页,分页尺寸,排序字段,排序参数等。这些参数我们可以通过request.getParameter()方式获取:

int page = null==request.getParameter("page") ? 1 : request.getParemeter("page");
//.....
PageBounds pageBounds = new PageBounds(page,limit);

也可以通过如下方式,对每个参数都通过参数绑定的形式获取:


@RequestMapping(value={"/index.action","/list.action"})
@RequiresAuthentication
public String list(Model model,@RequestParam(required =false,defaultValue ="1") int page,
@RequestParam(required =false,defaultValue ="15") int limit,
@RequestParam(required =false) String sort,
@RequestParam(required =false) String dir){
PageBounds pageBounds = new PageBounds(page, limit);
PageList couponList= (PageList) couponService.findByPage(pageBounds);
model.addAttribute("couponList", couponList);
model.addAttribute("page", couponList.getPaginator());
return "coupon/list";
}

但是,一个项目中,我们会有很多这样的分类,比如:产品列表分页,订单分页分页,会员列表分页。如果我们每个模块都用上面的方式去完成PageBounds的实例化,不仅影响代码的编写效率和可读性,也会造成很多代码的重复!

所以此处,我们可以使用HandlerMethodArgumentResolver 自定义解析器实现请求参数绑定,已达到自动注入PageBounds类型参数的效果:

@RequestMapping(value={"/index.action","/list.action"})
@RequiresAuthentication
public String list(Model model,PageBounds pageBounds){
PageList couponList= (PageList) couponService.findByPage(pageBounds);
model.addAttribute("couponList", couponList);
model.addAttribute("page", couponList.getPaginator());
return "coupon/list";
}

二、实现

2.1、自定义一个解析器,来解析PageBounds类型参数,代码中已注解说明:

package com.renyiwei.web.resolver;

import org.springframework.core.MethodParameter;

import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.github.miemiedev.mybatis.paginator.domain.PageBounds;

/**
* 自定义PageBounds方法参数解析器
*
* @author RenYiwei
*
*/
public class PageBoundsMethodArgumentResolver implements HandlerMethodArgumentResolver {

@Override
public boolean supportsParameter(MethodParameter parameter) {
// 获取参数类型
Class paramType = parameter.getParameterType();
// 如果该参数类型是PageBounds类自身或者子类,则返回true,表示这个解析器可以解析此类型
return PageBounds.class.isAssignableFrom(paramType);
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// 在此处通过request.getParameter()方式获取分页所需参数
//获取页码 这些字段可以通过自定义注解来指定
int page = null == webRequest.getParameter("page") ? 1 : new Integer(webRequest.getParameter("page"));
//获取分页尺寸
int limit = null == webRequest.getParameter("limit") ? 15 : new Integer(webRequest.getParameter("limit"));
//创建PageBounds实例 这里还可以传入排序方式等参数,构造更完美的PageBounds实例,此处为了简洁就以简单的为例
PageBounds pageBounds = new PageBounds(page,limit);
// 返回PageBounds实例,这个pageBounds就会以方法形参的方式传入控制器类的方法中
return pageBounds;
}

}

上面的PageBounds只是简单地构造了一下,还可以参入排序方式等参数来构造更完善的实例。

另外,也可以自定义注解,注解在方法参数中,来指定参数名称,默认值等,再通过methodParameter获取注解来读取自定义的值,这里就不作介绍了。

2.2、申明自定方法参数解析器,在springmvc的配置文件中配置,我的配置文件是spring-mvc.xml:







2.3、在控制器方法中指定参数为PageBounds类型,在调用service时可以直接传入:

@RequestMapping(value={"/index.action","/list.action"})
@RequiresAuthentication
public String list(Model model,PageBounds pageBounds){
PageList couponList= (PageList) couponService.findByPage(pageBounds);
model.addAttribute("couponList", couponList);
model.addAttribute("page", couponList.getPaginator());
return "coupon/list";
}

hibernate c3p0连接池断线自动重连

Messages:
1. Software caused connection abort: recv failed
2. Communications link failure The last packet successfully received from the server was 2,174,468 milliseconds ago. The last packet sent successfully to the server was 7 milliseconds ago.
3. could not execute query
File: org/hibernate/exception/SQLStateConverter.java
Line number: 99

原因分析:

造成该异常的原因是因为连接池中的连接已经超时失效,而程序在使用该连接的时候没有去检测该连接是否有效。

解决方案:

1、修改mysql的超时等待时间:

2、修改c3p0的配置,使程序在使用连接池之前对连接进行检测,如果无效,则重新获取连接。

例子:




struts2.1.8.1升级至2.3.24 修复GetShell漏洞

struts2.1.8.1升级至2.3.24步骤:

JAR包修改:

新增JAR包:

commons-lang3-3.2.jar

javassist-3.11.0.GA.jar

替换JAR包:

commons-fileupload-1.2.1.jar —->commons-fileupload-1.3.1.jar

commons-io-1.3.2.jar —–>commons-io-2.2.jar

commons-logging.jar —->commons-logging-1.1.3.jar(这个可不替换)

freemarker-2.3.15.jar —->freemarker-2.3.22.jar

ognl-2.7.3.jar —-> ognl-3.0.6.jar

struts2-core-2.1.8.1.jar —-> struts2-core-2.3.24.jar

struts2-spring-plugin-2.1.8.1.jar —-> struts2-spring-plugin-2.3.24.jar

xwork-core-2.1.6.jar —–> xwork-core-2.3.24.jar

JSON部分

json-lib-2.1.jar —-> json-lib-2.3-jdk15.jar

struts2-json-plugin-2.1.8.1.jar —->struts2-json-plugin-2.3.24.jar

struts2-junit-plugin-2.1.8.1.jar —->struts2-junit-plugin-2.3.24.jar

修改文档类型声明:

struts.xml的文档类型声明修改:

原来

现在

validator验证文档XxxxxAction-ActionName-validator.xml的文档类型声明修改:

原来:

现在:

出现的问题:

问题1:freemarker.core._TemplateModelException:net.sf.json.JSONException: Object is null

分析:原因是对象是null造成的,暂时通过属性过滤器判断value是否为null,null的话就过滤掉。(出现问题再找其他解决方案)

总结:

我升级的项目是基于SSH框架的,另外整合单点登录(cas)和WebService(cxf),除作上述修改调整和上述问题出现外,运行正常且没有出现其他问题,如后续出现其他问题,会继续更新。

Java不同类的属性拷贝(通过泛型和反射实现)

由于项目用到了WebService,客户端是用cxf自动生成的代码,有时候服务端的类对象,要转换到客户端的类对象上面去,而两者不是同一个类对象,但字段大体相似。总是通过setXXX(getXXX())总是显得有些臃肿和浪费时间,所以写了一个通过的方法,来实现转化,也实现了泛型。供参考,在赋值这一块,我只验证了二者的类型,没有做类型转换。

public static T copyProperty(H sourceObj,Class targetClass){
try {
T targetObj = targetClass.newInstance();
Field[] targetFields = targetClass.getDeclaredFields();
Field[] sourceFields = sourceObj.getClass().getDeclaredFields();
PropertyDescriptor sfpd = null;
Method readMehtod = null;
PropertyDescriptor tfpd = null;
Method setMethod = null;
for(Field targetField : targetFields){
for(Field sourceField:sourceFields){
if(targetField.getName().equals(sourceField.getName())){
sfpd =new PropertyDescriptor(sourceField.getName(), sourceObj.getClass());
readMehtod = sfpd.getReadMethod();
tfpd = new PropertyDescriptor(targetField.getName(), targetClass);
setMethod = tfpd.getWriteMethod();
//这里只是粗略地做了一下判断...
if(readMehtod.getReturnType().equals(setMethod.getParameterTypes()[0])){
setMethod.invoke(targetObj, readMehtod.invoke(sourceObj));
}
}
}
}
return targetObj;
} catch (Exception e) {
return null;
}
}

通过注解实现JSONPropertyFilter

 之前发表的文章涉及到JSONObject JSONArray属性过滤时,都是通过判断来实现的,那如果我们要在多处进行过滤的话,就会重复写很多代码,而且也不好修改。所以,这里我设计了一个注解annotation类,通过标注注解来实现JSONObject 和JSOnArray的属性过滤。

1、编写注解类


package com.renyiwei.wydns.json.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
*
* @author RenYiwei
*
*/
@Retention(RetentionPolicy.RUNTIME)
// 可以注解在字段,方法,类上
@Target({ ElementType.FIELD, ElementType.METHOD,ElementType.TYPE })
public @interface JSONPropertyFilter {

//默认注解了就是过滤
boolean Value() default true;
}

2、编写AnnotationPropertyFilter实现PropertyFilter


package com.renyiwei.wydns.json;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import net.sf.json.util.PropertyFilter;

import com.renyiwei.wydns.json.annotation.JSONPropertyFilter;

/**
*
* @author RenYiwei
*
*/
public class AnnotationPropertyFilter implements PropertyFilter {

public boolean apply(Object object, String name, Object value) {

// 通过读取注解来决定是否序列化
try {
// 获取类上的注解
JSONPropertyFilter clazzAnnotation = object.getClass().getAnnotation(JSONPropertyFilter.class);
// 如果类上有注解,并且值为true,表示需要过滤
if (clazzAnnotation != null && clazzAnnotation.Value()) {
// 不要这个字段 返回true
return true;
}
// 获取字段上的注解
Field field = object.getClass().getDeclaredField(name);
JSONPropertyFilter fieldAnnotation = field.getAnnotation(JSONPropertyFilter.class);
// 如果字段上注解了,并且值为true,表示需要过滤
if (null != fieldAnnotation && fieldAnnotation.Value()) {
// 不要这个字段 返回true
return true;
}

// 通过属性描述器 获取属性get方法的注解

PropertyDescriptor pd = new PropertyDescriptor(field.getName(), object.getClass());
Method getMethod = pd.getReadMethod();
if (null != getMethod) {
JSONPropertyFilter methodAnnotation = getMethod.getAnnotation(JSONPropertyFilter.class);
// 如果get方法上注解了,并且值为true,表示需要过滤
if (null != fieldAnnotation && fieldAnnotation.Value()) {
// 不要这个字段 返回true
return true;
}
}
} catch (NoSuchFieldException e) {
return false;
} catch (SecurityException e) {
return false;
} catch (IntrospectionException e) {
return false;
}

return false;
}

}

3、在javaBean上面标注注解


package com.renyiwei.wydns.domain;

import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.annotation.XmlTransient;

import com.renyiwei.wydns.json.annotation.JSONPropertyFilter;

public class Product {

private Long id;
//在产品系统的产品编号
private Long productid;
//在订单系统的产品编号
private Long orderpid;
private Long orderid;
private String name;
private String type;
private String extension;
//在这里标注
@JSONPropertyFilter
private Server server;
// 创建时间
private String createtime;
// 到期时间
private String expdate;
//购买时长
private String period;
//在这里标注
@JSONPropertyFilter
private Client client;
private Timestamp ordertime;
//省略get set方法
}

4、调用的时候传入AnnotationPropertyFilter对象


public String listAjax(){
List productList = productService.getAll();
Map returnMap = new HashMap();
JsonConfig config = new JsonConfig();
//在这里传入AnnotationPropertyFilter对象
config.setJsonPropertyFilter(new AnnotationPropertyFilter());
returnMap.put("results", productList);
returnObj = JSONObject.fromObject(returnMap,config);
return SUCCESS;
}

JAVA获取指定范围内可用的TCP端口

由于现在在做的项目需要获取tcp可用的端口,用于tomcat ajp协议的监听,然后更新nginx配置,由nginx利用ajp模块进行请求转发,所以需要获取本机上可用的tcp端口。

/**
* 获取可用的tcp端口号
* @return
*/
public static int getAvailableTcpPort(){
//指定范围10000到65535
for(int i=10000;i<=65535;i++){ try { new ServerSocket(i).close(); return i; } catch (IOException e) { //抛出异常表示不可以,则进行下一个 continue; } } return -1; }

对于Java网络编程,本人不是很精通,如果有更好的方法,请指点。