学习笔记之反射泛型信息和注解信息

本文用于记录学习笔记

获取子类传递的类型参数信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A<T>{
public A(){
super();
ParameterizedType pType = (ParameterizedType) this.getClass().getGenericSuperclass();//获取子类传递的类型参数信息
Type[] types = pType.pType.getActualTypeArguments();//得到类型数组
Class<?> c = (Class<?>) types[0];
System.out.println(c.getName());//输出类型信息
}
}

class B extends A<String>{

}
class C extends A<Integer> {

}
//测试方法
public void fun() {
new C();
}

结果:
java.lang.Integer

反射注解

  1. 要求
  • 注解保留策略必须是RetentionPolicy.RUNTIME
  1. 反射注解需要从作用目标上返回
  • 类上的注解,需要使用Class获取
  • 方法上的注解,需要使用Method获取
  • 实例域上的注解,需要使用Field获取
  • 构造器上的注解,需要使用Constructor获取
    Method、Field、Constructor都是(或者间接是)AccessibleObject的子类

方法
<T extends Annotation> T getAnnotation​(Class<T> annotationClass)Annotation[] getDeclaredAnnotations​()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Anno5(name = "name1", value = "value1")
Class A{
@Anno(name = "name2", value = "value2")
public void fun(){}
}
@Retention(RetentionPolicy.RUNTIME)
@interface Anno{
String name();
String value();
}

//测试代码,类上的注解
Class <A> c = A.class;
Anno anno1 = c.getAnnotation(Anno.class);
System.out.println(anno1.name() +"--" + anno1.value());//输出注解信息
//方法上的注解
Method m = c.getMethod("fun");//获取方法
Anno anno2 =m.getAnnotation(Anno.class);
System.out.println(anno2.name() + "--" + anno2.value());

结果:
name1--value1
name2--value2

xstream

本文用于记录学习笔记

XStream是什么

XStream是一个将对象序列化为XML并返回的简单库。

使用XStream

  1. 需要的jar包:xstream-1.4.10.jar,xpp3_min-1.1.4c.jar(XML Pull Parser,一款速度很快的解析器)。
  2. 使用步骤:
  • XStream xs =new XStream();
  • xs.toXML(Object);
    将成员变量如下的两个类转变为XML的结果
    1
    2
    private String pName;
    private List<City> cList = new ArrayList<>();
1
2
private String cName;
private String description;

输出:
1
十分的难看,因此需要对其进行简化。

<1>.给类名取个别名。

xstream.alias(String name, Class type);

<2>.将类的属性变成XML元素的属性。

xstream.useAttributeFor(Class definedIn, String fieldName);

<3>.将集合类属性去掉,保留集合内的元素生成的XML元素。

xstream.addImplicitCollection(Class ownerType, String fieldName);

<4>.去除不想要的属性。

xstream.omitField(Class definedIn,String fieldName);

完整代码:

1
2
3
4
5
6
7
8
9
List<Province> pList = getProvinces();//得到省的集合
XStream xs = new XStream();
//给类名元素取别名
xs.alias("china", List.class);
xs.alias("province", Province.class);
xs.alias("city", City.class);
xs.useAttributeFor(Province.class, "pName");//将Province的属性pName变成province元素的属性
xs.addImplicitCollection(Province.class, "cList");//将Province类的cList属性去掉,保留集合中的元素生成的XML元素
xs.omitField(CIty.class, "description");

简化之后:
2

学习笔记之java mail

本文用于记录学习心得和笔记。

邮件协议

SMTP:简单邮件传输协议,发邮件协议。服务器名称为smtp.xxx.xxx,端口号为25.
POP3:邮局协议第三版,收邮件协议。服务器名称pop3.xxx.xxx,端口号为110。
IMAP:因特网消息收发协议。

使用java mail发送邮件

需要的jar包:activation.jar,javax.mail.jar。
步骤:1. 创建邮件会话类Session 的实例,使用static Session getInstance(Properties props, Authenticator authenticator)方法,第一个参数类型为Properties,其中包含java mail规范的一些属性。例如:mail.host,mail.transport.protocol等。第二个参数是身份验证对象。2. 创建Mimemessage对象,通过调用其方法可以设置发件人,设置收件人,设置主题,设置内容。3. 发送,Transport.send(Message msg);
发送带有附件的邮件。这需要使用MimeMultipartMimeBodypart类。前者用来创建一个包含多部分的邮件体,后者表示邮件的主体部分。即在一个MimeMultipart对象中能添加多个MimeBodyPart。
完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Properties prop = new Properties();
prop.setProperty("mail.host", "smtp.qq.com");//设置服务器主机
prop.setProperty("mail.smtp.auth", "true");//设置需要验证
prop.setProperty("mail.smtp.ssl.enable", "true");//使用ssl连接
Authenticator anth = new Authenticator() {
//设置用户名、密码
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("wangyq97", "jrkeotaieoygeacj");
}
};
Session session = Session.getInstance(prop, anth);//创建邮件会话
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("[email protected]"));//发件人
message.setRecipients(RecipientType.TO, "[email protected]");//收件人
message.setSubject("标题");
// message.setContent("这是一封测试邮件", "text/html;charset=utf-8");
MimeMultipart list = new MimeMultipart();//创建包含多部分的邮件体
MimeBodyPart part1 = new MimeBodyPart();//主体部分
part1.setContent("文本部分", "text/html;charset=utf-8");//文本主体部分
list.addBodyPart(part1);
MimeBodyPart part2 = new MimeBodyPart();//主体部分
part2.attachFile(new File("F:/music/高梨康治 - 出陣.flac"));
part2.setFileName(MimeUtility.encodeText("出陣.flac"));//处理乱码问题
list.addBodyPart(part2);
message.setContent(list);
Transport.send(message);

学习笔记之下载

本文用于记录学习心得和笔记。

下载

下载就是向客户端响应字节数据。

步骤

设置Content-type响应头。可以通过this.getServletContext().getMimeType(String filename)方法来获取指定文件名的Mime类型。
设置Content-Disposition响应头。这个响应头的默认值是inline,即在浏览器窗口中打开。因此需要将其设置为attachment;filename=”文件名”。
创建文件输入流。FileInputStream input = new FileInputStream(File filename)
获取响应流,ServletOutputStream output = response.getOutputStream()
将输入流数据写入到响应流中。IOUtils.copy(input, output)
下载文件名乱码问题:大多数浏览器使用的是URL编码,因此当文件名是中文时会出现乱码,解决方式:name = new String(filenaem.getBytes("gbk"), ISO-8859-1)
完整代码:

1
2
3
4
5
6
7
8
9
10
11
String filename = "F:/music/山田タマル - Scarborough Fair.flac";//得到文件的Mime类型
String contentType = this.getServletContext().getMimeType(filename);//处理文件名乱码问题
String name = new String("斯卡布罗集市.flac".getBytes("gbk"), "ISO-8859-1");
String contentDisposition = "attachment;filename=" + name;
//设置响应头
response.setHeader("Content-Type", contentType);
response.setHeader("Content-Disposition", contentDisposition);
FileInputStream input = new FileInputStream(filename);//输入流
ServletOutputStream output = response.getOutputStream();//输出流
IOUtils.copy(input, output);//将数据从输入流写入到响应流中
input.close();

学习笔记之表单文件上传

本文用于记录学习心得和笔记。

上传文件时表单要求

  1. 请求方式post
  2. 设置enctype="multipart/form-data"
  3. 表单中添加文件表单项<input type="file" name="" />

Commons FileUpload处理文件上传

简介:FileUpload解析符合RFC 1867 “基于表单的HTML文件上传”的HTTP请求 。也就是说,如果使用POST方法提交HTTP请求,并且使用内容类型“multipart / form-data”,则FileUpload可以解析该请求,并以调用方容易使用的方式提供结果。

  1. 依赖包:commons-fileupload.jar, commons-io.jar
  2. 相关类:DiskFileItemFactory ,工厂;ServletFileUpload,解析器;FileItem,表单项;
  3. 使用:第一步,创建解析器工厂,
1
DiskFileItemFactory factory = new DiskFileItemFactory();

第二步,得到解析器,

1
ServletFileUpload fileUpload = new ServletFileUpload(factory);

第三步,使用ServletFileUpload的parseRequest方法解析请求,得到表单项的集合,

1
List<FileItem> list = fileUpload.parseRequest(request);

  1. FileItem类的常用方法:
    boolean isFormFiled() —是否是普通表单项
    String getFiledName() —返回表单项名称
    String getString(String encoding) —返回普通表单项的内容,参数是编码,不指定则为默认编码
    String getName() —返回上传的文件的名称
    int getSize() —返回上传文件的大小,单位是字节
    void write(File file) —将文件内容写入到指定的文件中

文件上传的细节

  1. 一般保存在WEB-INF目录下
    目的是不让浏览器直接访问到
  2. 文件名称相关问题
    有的浏览器上传的文件名带有绝对路径,这时要分割字符串
    文件名称重复问题,使用uuid + 文件名解决
    文件名称或普通表单项乱码问题,两种方式解决
    request.setcharacterEncoding("uft-8") //优先级低
    ServletFileUpload的方法public void setHeaderEncoding(String encoding) //优先级高
  3. 目录打散
    不能再一个目录下存放过多的文件,解决方法:哈希打散,获取文件名的hashCode,将其转换成16进制,然后取前2位用来生成二级目录。例如:1A2B3C4D则取1A生成/1/A来保存文件。
    代码如下:

    1
    2
    3
    4
    int hCode = filename.hashCode();
    String hex = Integer.toHexString(hCode); //转换成16进制
    File dirFIle = new File(path, charAt(0) + "/" + charAt(1)); //构建文件保存目录,其中path为保存文件的根目录
    dirFile.mkdirs(); //生成目录链
  4. 上传文件大小限制
    单个文件大小限制,setFileSizeMax(long fileSizeMax),当上传文件的大小超过指定的大小时会抛出异常
    整个请求所有文件大小限制,setSizeMax(long SizeMax),当请求上传的所有文件的总大小超过指定的大小时会抛出异常
    且这两个方法都必须在parseRequest()方法之前调用。

  5. 缓存大小与临时目录
    缓存大小默认是10kb,超出10kb就往硬盘上保存。
    往硬盘上暂时保存的目录即缓存目录。
    设置缓存大小和临时目录:使用DsikFIleItemFactory的有参构造器 DiskFileItemFactory(int sizeThreshold, File repository),第一个参数为缓存大小(字节),第二个参数为临时目录。
    More info: Deployment