获取访问者的IP、Calendar、判断socket是否已经断开及长连接、UDP丢包及无序问题、clob字段、Url请求方式中文乱码)
1、获取访问者的IP
public String getIp(HttpServletRequest request) {
String ip= request.getHeader("X-Forwarded-For");
if (ip== null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
ip= request.getHeader("Proxy-Client-IP");
if (ip== null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
ip= request.getHeader("WL-Proxy-Client-IP");
if (ip== null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
ip= request.getHeader("HTTP_CLIENT_IP");
if (ip== null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
ip= request.getHeader("HTTP_X_FORWARDED_FOR");
if (ip== null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
ip= request.getRemoteAddr();
if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)){
try {
ip= InetAddress.getLocalHost().getHostAddress();
}
catch (UnknownHostException e) {
e.printStackTrace();
}
}
return ip
}
/**
* 获取访问者IP
* 在一般情况下使用Request.getRemoteAddr()即可,但是经过nginx等反向代理软件后,这个方法会失效。
* 本方法先从Header中获取X-Real-IP,如果不存在再从X-Forwarded-For获得第一个IP(用,分割),
* 如果还不存在则调用Request .getRemoteAddr()。
*
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("X-Real-IP");
if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
return ip;
}
ip = request.getHeader("X-Forwarded-For");
if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个IP值,第一个为真实IP。
int index = ip.indexOf(',');
if (index != -1) {
return ip.substring(0, index);
} else {
return ip;
}
} else {
return request.getRemoteAddr();
}
}
2、Calendar
public class TestCalendar {
@Test
public void test(){
try {
Calendar calendar = new GregorianCalendar();//子类实例化
//获取年、月、日、时、分、秒、毫秒
System.out.println("年: "+calendar.get(Calendar.YEAR));
System.out.println("月 "+(calendar.get(Calendar.MONTH)+1));
System.out.println("日: "+calendar.get(Calendar.DAY_OF_MONTH));
System.out.println("时: "+calendar.get(Calendar.HOUR_OF_DAY));
System.out.println("分: "+calendar.get(Calendar.MINUTE));
System.out.println("秒: "+calendar.get(Calendar.SECOND));
System.out.println("毫秒 "+calendar.get(Calendar.MILLISECOND));
// 当前月第一天、最后一天
int currYear = calendar.get(Calendar.YEAR);
int currMonth = calendar.get(Calendar.MONTH) + 1;
System.out.print(currYear + "-" + currMonth);
SimpleDateFormat datef = new SimpleDateFormat("yyyy-MM-dd");
calendar.set(Calendar.DAY_OF_MONTH, 1);
Date beginTime = calendar.getTime();
String sTime = datef.format(beginTime) + " 00:00:00";
calendar.set(Calendar.DATE, 1);
calendar.roll(Calendar.DATE, -1);
Date endTime = calendar.getTime();
String eTime = datef.format(endTime) + " 23:59:59";
System.out.println("第一天"+sTime+"最后一天"+eTime);
Calendar cal = Calendar.getInstance();
//指定年月的的第一天、最后一天
int year = 2015;
int moth = 3;
cal.set(Calendar.YEAR,year);
cal.set(Calendar.MONTH, moth-1);
//当前月的最后一天
cal.set( Calendar.DATE, 1 );
cal.roll(Calendar.DATE, - 1 );
Date endTime2=cal.getTime();
String endTimeStr=datef.format(endTime2)+" 23:59:59";
//当前月的第一天
cal.set(GregorianCalendar.DAY_OF_MONTH, 1);
Date beginTime2=cal.getTime();
String beginTimeStr=datef.format(beginTime2)+" 00:00:00";
System.out.println("指定年月的的第一天"+endTimeStr+"最后一天"+beginTimeStr);
//当前时间的前一天
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd:HH");
String tmStr = "2015-5-18:00";
Date d = sdf2.parse(tmStr);
System.out.println(d);
Calendar now = Calendar.getInstance();
now.setTime(d);
now.set(Calendar.HOUR, now.get(Calendar.HOUR) -1);
System.out.println(sdf2.format(now.getTime()));
//最近N天
SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
cal.add(Calendar.DATE,-7);
System.out.println("最近7天"+df2.format(cal.getTime()));
Calendar ca2 =Calendar.getInstance();
//最近N个月
ca2.add(Calendar.MONTH,-1);//最近一个月
System.out.println("最近一个月"+df2.format(ca2.getTime()));
Calendar ca3 =Calendar.getInstance();
//最近N个年
ca3.add(Calendar.YEAR,-1);//最近一年
System.out.println("最近一年"+df2.format(ca3.getTime()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、判断socket是否已经断开
首先 socket类的方法isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()等,但经过试验并查看相关文档,这些方法都是本地端的状态,无法判断远端是否已经断开连接。然后想到是否可以通过OutputStream发送一段测试数据,如果发送失败就表 示远端已经断开连接,类似ping,但是这样会影响到正常的输出数据,远端无法把正常数据和测试数据分开。 最后又回到socket类,发现有一个方法sendUrgentData,查看文档后得知它会往输出流发送一个字节的数据,只要对方Socket的SO_OOBINLINE属性没有打开,就会自动舍弃这个字节,而SO_OOBINLINE属性默认情况下就是关闭的,所以正是我需要的。
于是,下面一段代码就可以判断远端是否断开了连接:
try{
socket.sendUrgentData(0xFF);
}catch(Exception ex){
reconnect();
}
用ping实现
package com.csdn.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class test {
static BufferedReader bufferedReader;
public static void main(String[] args) throws IOException {
try {
Process process = Runtime.getRuntime().exec("ping 192.168.1.104");//判断是否连接的IP;
bufferedReader = new BufferedReader(new InputStreamReader(process
.getInputStream()));
String connectionStr = "";
while ((connectionStr = bufferedReader.readLine()) != null) {
System.out.println(connectionStr);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
bufferedReader.close();
}
}
}
ping的方法有个严重的BUG,就是你只能判断对方是否连接网络,而不能判断客户端是否开启,
在写聊天室时经常要注意客户端异常退出的问题(比如客户直接调用任务管理器结束程序进程),
其实在通过socket.getoutstream和socket.getinputstream流对客户端发送、接受信息时如果socket没连接上是会抛出异常的,这也就是为什么Java会要求网络编程都要写在try里面,所以只要在catch里面写入客户端退出的处理就行了,没必要专门去想什么方法
socket长连接:
package com.yihongyu.exec.modules.crx.service.impl;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Iterator;
import java.util.Properties;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yihongyu.exec.modules.crx.manager.CrxNotificationManager;
import com.yihongyu.exec.modules.crx.service.CrxNotificationService;
import com.yihongyu.exec.modules.crx.service.CrxSocketClientService;
@Service
public class CrxSocketClientServiceImpl implements CrxSocketClientService {
private ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
@Autowired
private CrxNotificationService crxNotificationService;
private Socket socket;
private Properties props = new Properties();
private String host;
private String portStr;
/** 初始化Socket连接信息 */
@Override
@PostConstruct
public void init() {
try {
props.load(new FileInputStream("conf/notifications/crx.properties"));
host = props.getProperty("crx.host", "192.168.1.225");
portStr = props.getProperty("crx.port", "8222");
Integer port = Integer.parseInt(portStr);
connect(host, port);
} catch (FileNotFoundException e) {
LoggerFactory.getLogger(getClass()).error("无法找到Crx服务器配置文件,请检查是否存在文件:conf/notifications/crx.properties!");
} catch (IOException e) {
LoggerFactory.getLogger(getClass()).error("装载Crx服务器配置文件失败:conf/notifications/crx.properties!", e);
}
}
/** 创建Socket连接 */
@Override
public Boolean connect(String host, int port) {
try {
destroy();
this.socket = new Socket(host, port);
if (!isOrNotServerClose()) {
System.out.println("----------------Connection Crx socket success!----------------");
} else {
System.out.println("----------------Connection Crx socket fail!----------------");
LoggerFactory.getLogger(getClass()).error("Connection Crx socket fail!");
}
socket.setSoTimeout(60000);
socket.setKeepAlive(true);
isServerClose();
return socket.isConnected();
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
return false;
}
}
/** 检测服务端Socket是否断开 */
@Override
public void isServerClose() {
executor.schedule(new Runnable() {
@Override
public void run() {
try {
System.out.println("=================sendUrgentData=================");
socket.sendUrgentData(0XFF);
isServerClose();
} catch (IOException e) {// 出现异常,服务端主动断开
destroy();
isServerClose();
LoggerFactory.getLogger(getClass()).error("Crx Server Exception Close!");
LoggerFactory.getLogger(getClass()).error("重新向服务端发起连接");
reConnect();// 重新向服务端发起连接
e.printStackTrace();
}
}
}, 10000, TimeUnit.MILLISECONDS);
}
/** 重新创建连接 */
@Override
public boolean reConnect() {
try {
Integer port = Integer.parseInt(portStr);
this.socket = new Socket(host, port);
if (!isOrNotServerClose()) {
System.out.println("----------------Connection Crx socket success!----------------");
} else {
System.out.println("----------------Connection Crx socket fail!----------------");
LoggerFactory.getLogger(getClass()).error("Connection Crx socket fail!");
}
socket.setSoTimeout(60000);
socket.setKeepAlive(true);
return true;
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
return false;
}
}
@Override
public Boolean isOrNotServerClose() {
try {
socket.sendUrgentData(0XFF);
return false;
} catch (IOException e) {// 出现异常,服务端主动断开
LoggerFactory.getLogger(getClass()).error("Crx Server Exception Close!");
e.printStackTrace();
return true;
}
}
/** 向Crx服务端发送信息 */
@Override
public String process(String contentXml) {
try {
System.out.println("Send CrxNotification Xml: " + contentXml);
if (contentXml != null && contentXml.length() > 0) {
OutputStream out = this.socket.getOutputStream();
out.write(contentXml.getBytes("GBK"));
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/** 获取Crx服务端返回的信息 */
@Override
public String getCrxMsg() throws UnsupportedEncodingException, IOException {
// 服务端返回的消息状态: 0--发送成功, 1--发送失改, 2--超时
String crxServerMsg = null;
InputStream in = socket.getInputStream();
if (in.available() > 0) {
byte[] buff = new byte[in.available()];
in.read(buff);
crxServerMsg = new String(buff);
}
return crxServerMsg;
}
/** 关闭socket */
@Override
public void destroy() {
try {
if (this.socket != null) {
this.socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4、UDP丢包及无序问题
在项目中做了个验证程序.
发现客户端连续发来1000个1024字节的包,服务器端出现了丢包现象.
纠其原因,是服务端在还未完全处理掉数据,客户端已经数据发送完毕且关闭了.
有没有成熟的解决方案来解决这个问题.
我用过sleep(1),暂时解决这个问题,但是这不是根本解决办法,如果数据量大而多,网络情况不太好的话,还是有可能丢失.
你试着用阻塞模式吧...
select...我开始的时候好像也遇到过..不过改为阻塞模式后就没这个问题了...
采用回包机制,每个发包必须收到回包后再发下一个
UDP丢包是正常现象,因为它是不安全的。
丢包的原因我想并不是“服务端在还未完全处理掉数据,客户端已经数据发送完毕且关闭了”,而是服务器端的socket接收缓存满了(udp没有流量控制,因此发送速度比接收速度快,很容易出现这种情况),然后系统就会将后来收到的包丢弃。你可以尝试用setsockopt()将接收缓存(SO_RCVBUF)加大看看能不能解决问题。
服务端采用多线程pthread接包处理
UDP是无连接的,面向消息的数据传输协议,与TCP相比,有两个致命的缺点,一是数据包容易丢失,二是数据包无序。
要实现文件的可靠传输,就必须在上层对数据丢包和乱序作特殊处理,必须要有要有丢包重发机制和超时机制。
常见的可靠传输算法有模拟TCP协议,重发请求(ARQ)协议,它又可分为连续ARQ协议、选择重发ARQ协议、滑动窗口协议等等。
如果只是小规模程序,也可以自己实现丢包处理,原理基本上就是给文件分块,每个数据包的头部添加一个唯一标识序号的ID值,当接收的包头部ID不是期望中的ID号,则判定丢包,将丢包ID发回服务端,服务器端接到丢包响应则重发丢失的数据包。
模拟TCP协议也相对简单,3次握手的思想对丢包处理很有帮助。
udp是不安全的,如果不加任何控制,不仅会丢失包,还可能收到包的顺序和发送包的顺序不一样。这个必须在自己程序中加以控制才行。
收到包后,要返回一个应答,如果发送端在一定时间内没有收到应答,则要重发。
UDP本来存在丢包现象,现在的解决方案暂时考虑双方增加握手.
这样做起来,就是UDP协议里面加上了TCP的实现方法.
程序中采用的是pthread处理,丢包率时大时小,不稳定可靠
我感觉原因可能有两个,一个是客户端发送过快,网络状况不好或者超过服务器接收速度,就会丢包。
第二个原因是服务器收到包后,还要进行一些处理,而这段时间客户端发送的包没有去收,造成丢包。
解决方法:
方法一:客户端降低发送速度,可以等待回包,或者加一些延迟。
方法二:服务器部分单独开一个线程,去接收UDP数据,存放在一个缓冲区中,又另外的线程去处理收到的数据,尽量减少因为处理数据延时造成的丢包。
有两种方法解决楼主的问题:
方法一:重新设计一下协议,增加接收确认超时重发。(推荐)
方法二:在接收方,将通信和处理分开,增加个应用缓冲区;如果有需要增加接收socket的系统缓冲区。(本方法不能从根本解决问题,只能改善)
网络丢包,是再正常不过的了。
既然用UDP,就要接受丢包的现实,否则请用TCP。
如果必须使用UDP,而且丢包又是不能接受的,只好自己实现确认和重传,说白了,就是自己实现TCP(当然是部分和有限的简单实现)。
UDP是而向无连接的,用户在实施UDP编程时,必须制定上层的协议,包括流控制,简单的超时和重传机制,如果不要求是实时数据,我想TCP可能会更适合你!
5、
java读取clob字段的几种方法
第一种
Clob clob = rs.getClob("remark");//java.sql.Clob
String detailinfo = "";
if(clob != null){
detailinfo = clob.getSubString((long)1,(int)clob.length());
}
第二种:
Clob clob = rs.getClob("remark");//java.sql.Clob
int i = 0;
if(clob != null){
InputStream input = clob.getAsciiStream();
int len = (int)clob.length();
byte by[] = new byte[len];
while(-1 != (i = input.read(by, 0, by.length))){
input.read(by, 0, i);
}
detailinfo = new String(by, "utf-8");
}
第三种:
Clob clob = rs.getClob("remark");//java.sql.Clob
String value="";
String line="";
if(clob!=null){
Reader reader=((oracle.sql.CLOB)clob).getCharacterStream();
BufferedReader br=new BufferedReader(reader);
while((line=br.readLine())!=null){
value += line + "\r\n";
}
}
第一种方法代码量少,且能避免中文乱码问题;第二种方法与第一种方法效率差不多,也是常使用的一种方法;第三种方法效率极低,如果数据比较大的话建议不要使用。
6、Url请求方式中文乱码问题解决
jsp中post方式请求一般不会乱码,如果乱码加上这句:
解决办法一
request.setCharacterEncoding("utf-8");
而get方式请求,若url含非西欧编码必然会乱码,处理方式:
request.setCharacterEncoding("utf-8");
//将请求参数使用ISO-8859-1分解成字节数组,再将字节数组解码成字符串
String name = new String(request.getParamet("name").getBytes("ISO-8859-1"),"utf-8");
解决办法二
java.net.URLEncoder.encode()传送字符编码
面贴一下解决这个问题参考的文章:
使用java.net.URLEncoder.encode()可以对要传递的中文进行编码
a.在传参数之前先把参数进行转码:java.net.URLEncoder.encode(param);
取值时用语句java.net.URLDecoder.decode(param);再转回中文
b.在你的Tomcat目录-->conf目录-->server.xml里找出这段:
<Connector
port="8080" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443(www.111cn.net)" acceptCount="100"
debug="0" connectionTimeout="20000"
disableUploadTimeout="true"
<!--在里边加上这个参数-->
URIEncoding="gb2312" />
proto命令生成java类
1、下载 protoc-3.0.0-win32然后解压,解压后目录下有proto.exe文件,该文件用于生成java类
2、在proto.exe同一级文件夹下写.proto文件,例如:info.proto
3、cmd命令生成java类
用cd命令打开文件所在目录,例如文件在E:\sf-work\JAR\protoc\protoc-3.0.0-beta-2-win32下
E:
E:\>cd E:\sf-work\JAR\protoc\protoc-3.0.0-beta-2-win32
格式:[protoc.exe的目录][protoc.exe] [proto文件路径] --java_out=[生成java类输出目录]
E:\sf-work\JAR\protoc\protoc-3.0.0-beta-2-win32>protoc.exe ./info.proto --java_out=./
java通过反射获取属性字段名、值、数据类型
package cn.tzz.java.reflect;
import cn.tzz.aop.entity.Person;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Test;
public class TestReflect {
/** 方法--属性复制 */
public void fieldCopy(Object source, Object target) throws Exception {
Method[] methods = source.getClass().getDeclaredMethods();
for (Method method : methods) {
String methodName = method.getName();
System.out.println(methodName);
if (methodName.startsWith("get")) {
Object value = method.invoke(source, new Object[0]);
System.out.println(value);
String setMethodName = methodName.replaceFirst("(get)", "set");
Method setMethod = Person.class.getMethod(setMethodName,
method.getReturnType());
setMethod.invoke(target, value);
}
}
}
/** 属性字段名、值、数据类型 */
public void getFields(Object object) throws Exception {
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String classType = field.getType().toString();
int lastIndex = classType.lastIndexOf(".");
classType = classType.substring(lastIndex + 1);
System.out.println("fieldName:" + field.getName() + ",type:"
+ classType + ",value:" + field.get(object));
}
}
@Test
public void test() throws Exception {
Person person = new Person();
person.setId(1L);
person.setName("AAA");
Person person2 = new Person();
fieldCopy(person, person2);
getFields(person2);
}
}
通过System.getProperties()获取系统参数
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.junit.Test;
public class TestProperties {
/**获取所有系统属性*/
@Test
public void getALLSystemProperties(){
Map<Object, Object> map = new HashMap<Object, Object>();
Properties properties = System.getProperties();
Enumeration<Object> keys = properties.keys();
while (keys.hasMoreElements()) {
Object o = keys.nextElement();
map.put(o, properties.get(o));
}
for(Map.Entry<Object, Object> obj : map.entrySet()){
System.out.println(obj.getKey()+"-----"+obj.getValue());
}
}
/**获取具体的系统属性*/
@Test
public void getSystemProperties(){
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中的getGenericSuperclass方法的基本用法
通过getGenericSuperclass方法可以获取当前对象的直接超类的 Type
package cn.tzz.lang.clazz;
public class User {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class BaseHibernateDao<T,ID extends Serializable> {
private Class<T> clazz;
public BaseHibernateDao(){
//当前对象的直接超类的 Type
Type genericSuperclass = getClass().getGenericSuperclass();
if(genericSuperclass instanceof ParameterizedType){
//参数化类型
ParameterizedType parameterizedType= (ParameterizedType) genericSuperclass;
//返回表示此类型实际类型参数的 Type 对象的数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
this.clazz= (Class<T>)actualTypeArguments[0];
}else{
this.clazz= (Class<T>)genericSuperclass;
}
}
public Class<T> getClazz() {
return clazz;
}
}
public class UserService extends BaseHibernateDao<User, Integer>{
}
public class TestUserService {
public static void main(String[] args) {
UserService userService = new UserService();
System.out.println(userService.getClass());
}
}
运行结果:
class cn.tzz.lang.clazz.User