[[common-utils]]
= 常用工具

== Spring 上下文对象获取工具
net.parim.spark.common.spring.SpringUtil。
[source,java]
----
package net.parim.spark.common.spring;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
 * Spring 上下文对象获取工具
 * 
 *
 */
@Component
public class SpringUtil implements ApplicationContextAware {
	
	private static ApplicationContext applicationContext;
	
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		if(SpringUtil.applicationContext == null){
			SpringUtil.applicationContext = applicationContext;
		}
	}

	/**
	 * 获取applicationContext  
	 * @return
	 */
    public static ApplicationContext getApplicationContext() {  
       return applicationContext;  
    }  
  
    /**
     * 通过name获取 Bean.  
     * @param name Bean的名称
     * @return Bean对象或null
     */
    public static Object getBean(String name){  
       return getApplicationContext().getBean(name);  
    }  
  
    /**
     * 通过class获取Bean.  
     * @param clazz Class对象
     * @return Bean对象或null
     */
    public static <T> T getBean(Class<T> clazz){  
       return getApplicationContext().getBean(clazz);  
  
    }  
  
    /**
     * 通过name,以及Clazz返回指定的Bean  
     * @param name Bean的名称
     * @param clazz Class对象
     * @return Bean对象或null
     */
    public static <T> T getBean(String name,Class<T> clazz){  
       return getApplicationContext().getBean(name, clazz);  
    }  
}

----

== 字符串工具
=== StringUtils
org.apache.commons.lang.StringUtils 中方法的操作对象是java.lang.String类型的对象，是JDK提供的String类型操作方法的补充，并且是null安全的(即如果输入参数String为null则不会抛出NullPointerException，而是做了相应处理，例如，如果输入为null则返回也是null等，具体可以查看源代码)。

除了构造器，StringUtils中一共有130多个方法，并且都是static的，   

所以我们可以这样调用StringUtils.xxx()。 

== html处理
https://jsoup.org/[Jsoup]

== 对象工具
=== BeanUtils
==== 什么是BeanUtils工具

BeanUtils工具是一种方便我们对JavaBean进行操作的工具，是Apache组织下的产品。

==== BeanUtils工具一般可以方便javaBean的哪些操作？

1）beanUtils 可以便于对javaBean的属性进行赋值。

2）beanUtils 可以便于对javaBean的对象进行赋值。

3）beanUtils可以将一个MAP集合的数据拷贝到一个javabean对象中

==== 如何使用
[NOTE]
使用前提： 参数名称 需要和javabean的属性名称保持一致！！！！
[source,java]
----
public class Demo {  
  
    @Test  
    public void test1() throws IllegalAccessException, InvocationTargetException{  
          
        Person person = new Person();  
          
        BeanUtils.setProperty(person, "name", "xxxx");  
          
        System.out.println(person.getName());  
    }  
      
    @Test  
    public void test2() throws IllegalAccessException, InvocationTargetException{  
          
        String nameString = "aaa";  
        String passwordString = "123";  
        String age = "33";  
        String birthdayString = "1988-01-01";  
          
        Person person = new Person();  
        BeanUtils.setProperty(person, "name", nameString);  
        BeanUtils.setProperty(person, "password", passwordString);  
        BeanUtils.setProperty(person, "age", age);//只支持8种基本数据类型自动转换  
        //BeanUtils.setProperty(person, "birthday", birthdayString);  
          
        System.out.println(person.getName());  
        System.out.println(person.getPassword());  
        System.out.println(person.getAge());  
        //System.out.println(person.getBirthday());  
          
          
        //为了让日期赋到bean的birthday属性上，我们给beanUtils注册一个日期转换器  
        ConvertUtils.register(new Converter() {  
              
            @Override  
            public Object convert(Class type, Object value) {  
              
                if (value == null) {  
                    return null;  
                }  
                  
                if (!(value instanceof String)) {  
                    throw new ConversionException("只支持String类型的转换!");  
                }  
                  
                String str = (String)value;  
                  
                if (str.trim().equals("")) {  
                    return null;  
                }  
                  
                SimpleDateFormat df= new SimpleDateFormat("yyyy-MM-dd");  
                try {  
                    return df.parse(str);  
                } catch (ParseException e) {  
                    throw new RuntimeException(e);//异常链不能断  
                }  
            }  
        }, Date.class);  
          
          
        BeanUtils.setProperty(person, "birthday", birthdayString);  
        System.out.println(person.getBirthday());  
  
                Date date = person.getBirthday();  
        System.out.println(date.toLocaleString());  
    }  
}
----

=== ObjectUtils
org.apache.commons.lang3.ObjectUtils类重新实现了toString,equals，hashcode生成策略等方法，增加了null对象的处理，对象的比较，一组对象中对象的频繁出现，最佳猜测策略，克隆的方法。

'''

ObjectUtils类的基本static方法：

|====
| defaultIfNull(T,  T) | 参数1为null,用参数2代替
| firstNonNull(T...) | 获取指定参数列表中第一个不为null的元素
| equals(Object, Object) |   
| notEqual(Object, Object) |   
| hashCode(Object) |   
| hashCodeMulti(Object...) | 多对象hashcode生成策略
| identityToString(Object) |   
| identityToString(StringBuffer, Object) |   
| toString(Object) |   
| toString(Object, String) |   
| min(T...) | 获取指定参数列表中最小的元素
| max(T...) | 获取指定参数列表中最大的元素
| compare(T, T) | 比较两个参数大小，默认null小于任何不为null的值
| compare(T, T, boolean) | 比较两个参数大小，参数3设置null的大小，false为小于任何不为null的值true相反
| median(T...) | 以最佳猜测的方式获取参数列表中的中间值，如果列表数为偶数，则中间值取低位的值
| median(Comparator<T>,  T...) | 重载方法，提供最佳猜测的排序策略
| mode(T...) | 获取参数列表中最频繁出现的项
| clone(T) |   
| cloneIfPossible(T) |   
|====
[NOTE]
另：org.springframework.util.ObjectUtils也提供了一些方法方便使用

== DTO工具
modelmapper

== 文件工具
=== Apache commons io
==== FileUtils
org.apache.commons.io.FileUtils 提供了很多方便文件操作的方法，如文件读写、文件递归查找、文件复制、文件移动等。

==== FilenameUtils
org.apache.commons.io.FilenameUtils 是一个通用的文件名和文件路径处理工具集，它是为了避免从Windows开发环境到*nix环境可能会出现的与文件路径有关的问题。

=== Zip
由于jdk提供的zip工具在处理中文文件时会产生乱码，所以Zip文件的压缩与解压请使用net.parim.spark.common.utils.zip.ZipUtil

=== MP4
==== https://github.com/sannies/mp4parser[mp4parser]
==== ffmpeg

== 日期处理

=== JodaTime +
JodaTime是一个强大的日期处理工具，已经纳入JDK8，在对日期进行处理时应优先使用Jodatime。

==== 获取今天的开始时间

[source,java]
----
DateTime nowTime = new DateTime();

DateTime startOfDay =  nowTime.withTimeAtStartOfDay(); 

----
==== 获取今天的结束时间

[source,java]
----
DateTime nowTime = new DateTime();

DateTime endOfDay =  nowTime.millisOfDay().withMaximumValue(); 

----

==== 获取现在距离今天结束还有多长时间
[source,java]
----
DateTimenowTime = new DateTime();

DateTime endOfDay = nowTime.millisOfDay().withMaximumValue();

endOfDay.getMillis()-nowTime.getMillis();
----
==== 计算两个日期的相隔天数
[source,java]
----
DateTime nowTime = new DateTime();

DateTime futureTime = new DateTime(2015, 10, 1, 0, 0, 0);

Int days = Days.daysBetween(nowTime, futureTime).getDays();
----
[NOTE]
推荐文章： http://www.ibm.com/developerworks/cn/java/j-jodatime.html[http://www.ibm.com/developerworks/cn/java/j-jodatime.html] + 
官方地址： http://www.joda.org/joda-time/[http://www.joda.org/joda-time/]

=== PrettyTime
当你希望能够将时间格式成易于用户阅读的格式，如"12分钟前"、"2天前"、"至今3个月"等，那么你可以用 PrettyTime 来处理。 对PrettyTiem进行简单的封装，在格式化时根据Spring管理的的Locale对象进行国际化显示。 + 
[source,java]
----
package net.parim.spark.common.utils.time;

import java.util.Date;
import java.util.Locale;

import org.apache.commons.lang3.StringUtils;
import org.ocpsoft.prettytime.PrettyTime;
import org.ocpsoft.prettytime.units.JustNow;
import org.ocpsoft.prettytime.units.Millisecond;
import org.ocpsoft.prettytime.units.Second;
import org.springframework.context.i18n.LocaleContextHolder;

/**
 * 日期显示人性化
 * @author jiawei
 *
 */
public class PrettyTimeUtil {

	private final static PrettyTime PRETTY_TIME = new PrettyTime();
	static{
	  PRETTY_TIME.removeUnit(JustNow.class);//去除“片刻之前”
	  PRETTY_TIME.removeUnit(Second.class);// 去除显示秒
	  PRETTY_TIME.removeUnit(Millisecond.class);// 去除显示毫秒
	}
	public static String format(Date date) {
		Locale locale = LocaleContextHolder.getLocale();
		PRETTY_TIME.setLocale(locale);
		// 如果是中文语言，去除结果中的空格字符
		if(locale.getLanguage().equals(new Locale("zh").getLanguage())){
			return StringUtils.remove(PRETTY_TIME.format(date), " ");
		}
		return PRETTY_TIME.format(date);
	} 
}
----
如何使用？
[source,java]
----
PrettyTimeUtil.format(new Date());
----

=== 发送邮件

==== 邮件相关设置获取
参见 net.parim.spark.core.system.setting.service.EmailSettingService。
`findEmailSettingMap()` 返回与邮件设置有关的Map对象，相关的key值可以通过`EmailSettingService`的静态成员变量获取。
[NOTE]
构造邮件收件人时应根据`email.to.limit`设置

==== 简单邮件
[source,java]
----
    @Autowired
	EmailSender emailSender;
	public void sendSimpleMailMessage() {
		SimpleMailMessage message = new SimpleMailMessage();
		message.setFrom("jiawei@parim.net");
		message.setTo("jiawei@parim.net");
		message.setSubject("标题：测试标题");
		message.setText("测试内容部份");
		emailSender.send(message);
	}
----

==== html邮件发送
[source,java]
----
    @Autowired
	EmailSender emailSender;
	public void testSendMimeMessage() {
		MimeMessage mimeMessage = emailSender.createMimeMessage();

		try {
			MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
			// 基本设置.
			helper.setFrom("jiawei@parim.net");// 发送者.
			helper.setTo("jiawei@parim.net");// 接收者.
			helper.setSubject("标题：发送Html内容");
			StringBuffer sb = new StringBuffer();
			sb.append("<h1>大标题-h1</h1>").append("<p style='color:#F00'>红色字</p>")
					.append("<p style='text-align:right'>右对齐</p>");
			helper.setText(sb.toString(), true);
		} catch (MessagingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		emailSender.send(mimeMessage);
		/*
		 * // 嵌入图片并显示在邮件正文-- Begin
		 * 
		 * helper.setSubject("测试静态资源（邮件主题）");// 邮件主题. // 邮件内容，第二个参数指定发送的是HTML格式
		 * // 说明：嵌入图片<img src='cid:head'/>，其中cid:是固定的写法，而head是一个contentId。
		 * helper.setText("<body>这是图片：<img src='cid:head' /></body>", true);
		 * FileSystemResource file = new FileSystemResource(new
		 * File("D:/test/head/head1.jpg")); helper.addInline("head", file);
		 * helper.setText(sb.toString(), true); emailSender.send(mimeMessage);
		 * // 嵌入图片并显示在邮件正文-- End
		 */

	}
----

== 获取客户端类型-UserAgentUtil

在开发过程中，可能会碰到需要获取客户端信息的需求，比如登录，学习等，如果自己去解析`User-Agent`,费时又费力，所以项目中使用了第三方的开源工具 https://github.com/nielsbasjes/yauaa[yauaa] ，在此感谢作者 nielsbasjes。

=== 示例输出
User-Agent 信息

    Mozilla/5.0 (Linux; Android 7.0; Nexus 6 Build/NBD90Z) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36

上面的信息会转换成下表

[width="100%",options="header"]
|====================
| 字段名称 | 值 
|  **Device**Class                      | 'Phone'                
|  **Device**Name                       | 'Google Nexus 6'       
|  **Device**Brand                      | 'Google'               
|  **OperatingSystem**Class             | 'Mobile'               
|  **OperatingSystem**Name              | 'Android'              
|  **OperatingSystem**Version           | '7.0'                  
|  **OperatingSystem**NameVersion       | 'Android 7.0'          
|  **OperatingSystem**VersionBuild      | 'NBD90Z'               
|  **LayoutEngine**Class                | 'Browser'              
|  **LayoutEngine**Name                 | 'Blink'                
|  **LayoutEngine**Version              | '53.0'                 
|  **LayoutEngine**VersionMajor         | '53'                   
|  **LayoutEngine**NameVersion          | 'Blink 53.0'           
|  **LayoutEngine**NameVersionMajor     | 'Blink 53'             
|  **Agent**Class                       | 'Browser'              
|  **Agent**Name                        | 'Chrome'               
|  **Agent**Version                     | '53.0.2785.124'        
|  **Agent**VersionMajor                | '53'                   
|  **Agent**NameVersion                 | 'Chrome 53.0.2785.124' 
|  **Agent**NameVersionMajor            | 'Chrome 53'            
|====================

=== 使用方法
yauaa获取相关属性需要通过UserAgent的getValue(String name)方法，书写UserAgentUtil将常用的属性获取封装成方法
[source,java]
----
public Boolean checkCourse(@PathVariable("courseId") Long courseId,
			@RequestParam(name = "classroomId",required = false) Long classroomId,
		@CurrentUser UserToken userToken, HttpServletRequest request) {
	
	UserAgentUtil userAgent = UserAgentUtil.build().parse(request.getHeader("User-Agent"));
	playService.check(courseId, classroomId, userToken.getUser(), userAgent);
	return true;
}
----

