Spring定时邮件功能

背景:员工时间段内工作汇报以及考勤信息统计,邮件提醒(每周一和周五邮件提醒)

数据库部分不做说明了,这里仅总结记录java部分的实现。重点是记录自己在java方面的实践。

DAO层设计以及代码

NoteMailMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.**.smarteam.web.background.dao.NoteMailMapper"><resultMap type="java.util.Map" id="map"></resultMap><!-- 查询数据 --><select id="getData" resultType="map" parameterType="map">SELECT a.username username, a.deptname deptname, a.userid userid, a.unit_id unitId,IFNULL(b.costs,0) costs,IFNULL(c.standard_times,0) standardTimes,concat(CASE WHEN IFNULL(c.standard_times,0) > 0 THEN ROUND((b.costs/c.standard_times)*100,2)ELSE ''END,'%') AS notesRate, IFNULL(c.oacosts,0) oacosts,concat(CASE WHEN IFNULL(c.standard_times,0) > 0 THEN ROUND((c.oacosts/c.standard_times)*100,2)ELSE ''END,'%') AS oaRate,concat(CASE WHEN IFNULL(c.oacosts,0) > 0 THEN ROUND((b.costs/c.oacosts)*100,2)ELSE ''END,'%') AS notesoaRateFROM(SELECT m.NAME username, u.NAME deptname, p.ID userid, u.id unit_idFROM org_member m LEFT JOIN org_principal pON p.MEMBER_ID = m.IDLEFT JOIN org_unit uON u.id = m.ORG_DEPARTMENT_IDWHERE u.PATH LIKE '0000000300030006%' AND p.id IS NOT NULL AND p.IS_ENABLE = 1 ORDER BY 2) aLEFT JOIN (SELECT created_by, IFNULL(SUM(cost),0) costsFROM project_notes_tbWHERE notes_time <![CDATA[>=]]> #{startDate}AND notes_time <![CDATA[<=]]> #{endDate}GROUP BY created_by) bON a.userid = b.created_byLEFT JOIN (SELECT IFNULL(ROUND(SUM(oacosts),1),0) oacosts , login_id , (SELECT SUM(a.standard_time) standard_timesFROM (SELECT holiday, holiday_type, CASE holiday_type WHEN 0 THEN 8ELSE 0END AS standard_timeFROM kpi_holidays) aWHERE a.holiday <![CDATA[>=]]> #{startDate}AND a.holiday <![CDATA[<=]]> #{endDate}) standard_timesFROM oa_costs_viewWHERE card_date <![CDATA[>=]]> #{startDate}AND card_date <![CDATA[<=]]> #{endDate}GROUP BY login_id)cON c.login_id = b.created_by<where><if test="deptId!=null and deptId!=''">a.unit_id = #{deptId}AND a.userid NOT IN (SELECT p.ID FROM org_principal pLEFT JOINorg_member mON p.MEMBER_ID = m.IDLEFT JOIN org_level lON l.ID = m.ORG_LEVEL_IDWHERE m.ORG_DEPARTMENT_ID = #{deptId}AND l.LEVEL_ID = (SELECT MIN(l.LEVEL_ID)FROM org_principal pLEFT JOINorg_member mON p.MEMBER_ID = m.IDLEFT JOIN org_level lON l.ID = m.ORG_LEVEL_IDWHERE m.ORG_DEPARTMENT_ID = #{deptId}GROUP BY m.ORG_DEPARTMENT_ID))</if></where>ORDER BY notesRate DESC</select><!-- 查询数据记录数 --><select id="countData" resultType="int" parameterType="map">SELECT count(*)FROM(SELECT m.NAME username, u.NAME deptname, p.ID userid, u.id unit_idFROM org_member m LEFT JOIN org_principal pON p.MEMBER_ID = m.IDLEFT JOIN org_unit uON u.id = m.ORG_DEPARTMENT_IDWHERE u.PATH LIKE '0000000300030006%' AND p.id IS NOT NULL AND p.IS_ENABLE = 1 ORDER BY 2) aLEFT JOIN (SELECT created_by, IFNULL(SUM(cost),0) costsFROM project_notes_tbWHERE notes_time <![CDATA[>=]]> #{startDate}AND notes_time <![CDATA[<=]]> #{endDate}GROUP BY created_by) bON a.userid = b.created_byLEFT JOIN (SELECT IFNULL(ROUND(SUM(oacosts),1),0) oacosts , login_id , (SELECT SUM(a.standard_time) standard_timesFROM (SELECT holiday, holiday_type, CASE holiday_type WHEN 0 THEN 8ELSE 0END AS standard_timeFROM kpi_holidays) aWHERE a.holiday <![CDATA[>=]]> #{startDate}AND a.holiday <![CDATA[<=]]> #{endDate}) standard_timesFROM oa_costs_viewWHERE card_date <![CDATA[>=]]> #{startDate}AND card_date <![CDATA[<=]]> #{endDate}GROUP BY login_id)cON c.login_id = b.created_by<where><if test="deptId!=null and deptId!=''">a.unit_id = #{deptId}</if></where></select><!-- 获取技术体系所有的叶子部门 --><select id="getAllTechLeafDept" resultMap="map">SELECT id , nameFROM org_unitWHERE PATH LIKE '0000000300030006%'AND IS_ENABLE = 1AND CHAR_LENGTH(path) >= 28</select><!-- 获取部门领导数量 若数据不等于1 则该部门没有领导 --><select id="countLeaders" parameterType="long" resultType="int">SELECT count(*)FROM org_principal pLEFT JOINorg_member mON p.MEMBER_ID = m.IDLEFT JOIN org_level lON l.ID = m.ORG_LEVEL_IDWHERE m.ORG_DEPARTMENT_ID = #{deptId}AND l.LEVEL_ID = (SELECT MIN(l.LEVEL_ID)FROM org_principal pLEFT JOINorg_member mON p.MEMBER_ID = m.IDLEFT JOIN org_level lON l.ID = m.ORG_LEVEL_IDWHERE m.ORG_DEPARTMENT_ID = #{deptId}GROUP BY m.ORG_DEPARTMENT_ID) </select><!-- 获取部门领导信息 --><select id="getLeaderInfo" resultMap="map" parameterType="long"> SELECT p.ID userid, m.ORG_DEPARTMENT_ID deptId, l.LEVEL_ID levelId, p.LOGIN_NAME username, m.EXT_ATTR_2 usermailFROM org_principal pLEFT JOINorg_member mON p.MEMBER_ID = m.IDLEFT JOIN org_level lON l.ID = m.ORG_LEVEL_IDWHERE m.ORG_DEPARTMENT_ID = #{deptId}AND l.LEVEL_ID = (SELECT MIN(l.LEVEL_ID)FROM org_principal pLEFT JOINorg_member mON p.MEMBER_ID = m.IDLEFT JOIN org_level lON l.ID = m.ORG_LEVEL_IDWHERE m.ORG_DEPARTMENT_ID = #{deptId}GROUP BY m.ORG_DEPARTMENT_ID)</select></mapper>

Serveice层设计以及代码

NoteMailMapper.java

package com.**.smarteam.web.background.dao;

import java.util.List;import java.util.Map;public interface NoteMailMapper {/** * 获取汇报统计数据 * @param map * @return */List<Map> getData(Map map);/** * 获取汇报统计数据的记录数 * @param map * @return */int countData(Map map);/** * 获取技术体系所有的叶子部门 id name * @return */List<Map> getAllTechLeafDept();/** * 获取部门领导数量 若数据不等于1 则该部门没有领导 * @param deptId * @return */int countLeaders(long deptId);/** * 获取部门领导信息 * @param deptId * @return */Map getLeaderInfo(long deptId);}

Service层设计代码

接口NoteMailService.java

package com.**.smarteam.web.background.service;

import java.util.List;import java.util.Map;import javax.mail.Session;import javax.mail.internet.MimeMessage;public interface NoteMailService {/** * 获取技术体系所有的叶子部门列表信息 id name * @return */List<Map> getAllDeptList();/** * 判断该部门是不是有部门领导 * @param deptId * @return */boolean hasLeader(Long deptId);/** *获取领导信息 * @param deptId * @return */Map getLeaderInfo(long deptId);/** * 获取部门的汇报考勤统计数据 * @param deptId * @return */List<Map> getData(long deptId);/** * 获取部门的汇报考勤统计数据 de 记录数 * @param long deptId * @return */int countData(long deptId);/** * 生成邮件正文 * @param deptId * @return */String mailBody(Map params);/** * 生成邮件MimeMessage * @param session * @param deptId * @return * @throws Exception */MimeMessage createMail(Session session,Map map)throws Exception;boolean sendMail(Map map);}
NoteMailServiceImpl.java 实现
package com.**.smarteam.web.background.service.impl;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apache.http.impl.client.TunnelRefusedException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.**.smarteam.core.common.DateUtils;
import com.**.smarteam.web.background.dao.NoteMailMapper;
import com.**.smarteam.web.background.service.NoteMailService;
@Service
public class NoteMailServiceImpl implements NoteMailService {
	@Autowired
	private NoteMailMapper noteMailMapper;

	@Override
	public List<Map> getAllDeptList() {
		
		return noteMailMapper.getAllTechLeafDept();
	}

	@Override
	public boolean hasLeader(Long deptId) {
		return 1 == noteMailMapper.countLeaders(deptId) ? true : false;
	}
	
	@Override
	public Map getLeaderInfo(long deptId) {
		// TODO Auto-generated method stub
		return noteMailMapper.getLeaderInfo(deptId);
	}

	@Override
	public List<Map> getData(long deptId) {
		Map map  = new HashMap();
		map.put("deptId", deptId);
		//date
		List<String> startAndEndDate = DateUtils.getStartAndEndDate();
		map.put("startDate", startAndEndDate.get(0));
		map.put("endDate", startAndEndDate.get(1));
		
		return noteMailMapper.getData(map);
	}

	@Override
	public int countData(long deptId) {
		Map map  = new HashMap();
		map.put("deptId", deptId);
		//date
		List<String> startAndEndDate = DateUtils.getStartAndEndDate();
		map.put("startDate", startAndEndDate.get(0));
		map.put("endDate", startAndEndDate.get(1));
		
		return noteMailMapper.countData(map);
	}

	@Override
	public boolean sendMail(Map map) {
		System.out.println("===========sendMail============");
		boolean flag = false;
		try {
			Properties prop = new Properties();
	        prop.setProperty("mail.host", "smtp.voole.com");
	        prop.setProperty("mail.transport.protocol", "smtp");
	        prop.setProperty("mail.smtp.auth", "true");
	        Session session = Session.getInstance(prop);
	        Transport ts = session.getTransport();
	        ts.connect("mail.voole.com", "[email protected]", "DevOps2017voole");
	        Message message = createMail(session,map);
	        ts.sendMessage(message, message.getAllRecipients());
	        ts.close();
	        flag = true;
		} catch (Exception e) {
			flag = false;
			e.printStackTrace();
			System.out.println("邮件发送失败!");
		}
		
		return flag;
		
	}
	
	@Override
	public MimeMessage createMail(Session session,Map map) throws Exception{
		System.out.println("===========createMail============");
		MimeMessage message = new MimeMessage(session);
		long deptId = (long) map.get("deptId");
		String mForm = (String) map.get("mFrom");
		String mSubject = (String) map.get("mSubject");
		String deptName = (String) map.get("deptName");
		Map leader = getLeaderInfo(deptId);
        message.setFrom(new InternetAddress(mForm));
        StringBuffer bfBuffer =  new StringBuffer();
        bfBuffer.append(leader.get("usermail").toString());
        bfBuffer.append(",");
        bfBuffer.append("***@voole.com");
        InternetAddress[] address = new InternetAddress().parse(bfBuffer.toString());
        message.setRecipients(Message.RecipientType.TO,address);
//        message.setRecipients(Message.RecipientType.TO,"***@voole.com");
//        message.setRecipients(Message.RecipientType.TO,leader.get("usermail").toString());
        message.setSubject(mSubject);
        message.setContent(mailBody(map), "text/html;charset=UTF-8");
        return message;
	}
	
	@Override
	public String mailBody(Map params) {
		long deptId = (long) params.get("deptId");
		String deptName = (String) params.get("deptName");
		System.out.println("===========mailBody============");
		StringBuffer bodyBuffer = new StringBuffer();
		String[] head = {"deptname", "username", "costs", "standardTimes", "notesRate", "oacosts", "oaRate", "notesoaRate"};
		List<Map> dataList = getData(deptId);
		List<String> startAndEndDate = DateUtils.getStartAndEndDate();
		
		bodyBuffer.append("<html><head></head><body>"
				+ "你好,</br>"
				+ "您的部门<b>"+deptName+"</b>人员在"
				+ startAndEndDate.get(0) + "--" + startAndEndDate.get(1)
				+ "的devops汇报工时以及考勤统计如下:</br>"
				+ "<table border=1>"
				+ "<tr>"
				+ "<th>部门名称</th>"
				+ "<th>姓名</th>"
				+ "<th>汇报工时</th>"
				+ "<th>标准工时</th>"
				+ "<th>汇报率(汇报工时/标准工时)</th>"
				+ "<th>考勤工时</th>"
				+ "<th>出勤率(考勤工时/标准工时)</th>"
				+ "<th>考勤汇报率(汇报工时/考勤工时)</th>"
				+ "</tr>");
		
		for(int i=0; i<dataList.size(); i++){
			bodyBuffer.append("<tr>");
			Map map = dataList.get(i);
			for(int j=0; j<head.length; j++){
				bodyBuffer.append("<td>");
				bodyBuffer.append(map.get(head[j]));
				bodyBuffer.append("</td>");
			}
			bodyBuffer.append("</tr>");
		}
		bodyBuffer.append("</table>");
		bodyBuffer.append("</br></br>"
				+ "Devops系统提醒邮件!"
				+ "</br>");
		bodyBuffer.append("</body></html>");
		
		return bodyBuffer.toString();
	}
}

Service层功能Junit测试

package com.eliteams.quick4j.test.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.**.smarteam.web.background.service.NoteMailService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:applicationContext-shiro.xml","classpath:applicationContext.xml",
	"classpath:spring-mvc.xml","classpath:mybatis-config.xml"})
public class NoteMailServiceTest {

	@Autowired
	private NoteMailService noteMailService;
	
	@Test
	public void test(){
		List<Map> deptList = noteMailService.getAllDeptList();
		System.out.println("------------------size--------" + deptList.size());
		for (int i=0; i<deptList.size(); i++) {
			System.out.println("================deptList.get(i)==============" + deptList.get(i));
			Map map = deptList.get(i);
			long deptId = (long) map.get("id");
			String deptName = (String) map.get("name");
			if (!noteMailService.hasLeader(deptId)) {
				continue;
			}
			Map mailMap = new HashMap();
			mailMap.put("deptId", deptId);
			mailMap.put("deptName", deptName);
			mailMap.put("mFrom", "**@**.com");
			mailMap.put("mSubject", "**部门汇报及考勤统计提醒");
			
			if(noteMailService.sendMail(mailMap)){
				continue;
			}else {
				--i;
				continue;
			}
		}
	}
}

如果serviceTest跑通调试功能没问题,继续下一步Controller层代码设计开发。实际controller层代码几乎和ServiceTest一样。

Controller层设计以及代码

package com.**.smarteam.web.background.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
/**
 * 技术体系汇报考勤统计邮件提醒
 */
import org.springframework.stereotype.Controller;

import com.**.smarteam.web.background.service.NoteMailService;
import com.**.smarteam.web.project.service.NoteOAReportService;

@Controller
public class NoteMailController {
	
	@Autowired
	private NoteMailService  noteMailService;
	
	public void sendNoteMail() {
		List<Map> deptList = noteMailService.getAllDeptList();
		for (int i=0; i<deptList.size(); i++) {
			System.out.println("================deptList.get(i)==============");
			Map map = deptList.get(i);
			long deptId = (long) map.get("id");
			String deptName = (String) map.get("name");
			if (!noteMailService.hasLeader(deptId)) {
				continue;
			}
			Map mailMap = new HashMap();
			mailMap.put("deptId", deptId);
			mailMap.put("deptName", deptName);
			mailMap.put("mFrom", "**@**.com");
			mailMap.put("mSubject", "**部门汇报及考勤统计提醒");
			
			if(noteMailService.sendMail(mailMap)){
				continue;
			}else {
				--i;
				continue;
			}
		}
	}
}

工具代码

package com.**.smarteam.core.common;
/**
 * by zfy 2018-05-10
 */
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

public class DateUtils {
	
	private static final int START_DATE = 20;
	/**
	 * 获取起始和结束时间
	 * 结束时间为当前的日期
	 * 起始时间为:若当前日期大于19号 则起始时间为当前月份的20号;
	 * 			若当前日期小于等于19号,则起始时间为上月的20号;
	 *      注意年份的变更
	 * @return List index 0 is startDate 
	 * 				index 1 is endDate
	 */
	public static  List<String> getStartAndEndDate() {
		List<String> list = new ArrayList<String>();
		LocalDate ld = LocalDate.now();
		LocalDate startDate = null;
		int monDay = ld.getDayOfMonth();
		int mon = ld.getMonthValue();
		int year = ld.getYear();
		
		if (monDay<=19) {
			if (12 == mon) {
				mon = 1;
				year = year - 1;
			}else {
				mon = mon - 1;
			}
			startDate = LocalDate.of(year, mon, START_DATE);
		}else{
			startDate.of(year, mon, START_DATE);
		}
		
		list.add(startDate.toString());
		list.add(ld.toString());
		
		return list;
	}
}

配置spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd 
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">


    <!-- 扫描controller(controller层注入) -->
    <context:component-scan base-package="com.**.smarteam.web.background.controller"/>
    <!-- 启用spring mvc 注解 -->
	<mvc:annotation-driven />
    
<!--     会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是spring MVC为@Controllers分发请求所必须的 -->




    <!-- 对模型视图添加前后缀 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/views/" p:suffix=".jsp"/>


    <!-- 配置springMVC处理上传文件的信息 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8"/>
        <property name="maxUploadSize" value="10485760000"/>
        <property name="maxInMemorySize" value="40960"/>
    </bean>


    <!-- 启用shrio授权注解拦截方式 -->
    <aop:config proxy-target-class="true"></aop:config>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>


	<!-- 定时器 线程池-->
	<bean id="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
	 	<property name="corePoolSize" value="10" />
	 	<property name="maxPoolSize" value="100" />
	 	<property name="queueCapacity" value="500" />
	</bean>
	<!-- 另外一个邮件定时任务 -->
	<bean id="bizObject" class="com.voole.smarteam.web.background.controller.MailController"/>
	<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
	 	<property name="targetObject" ref="bizObject" />
	 	<property name="targetMethod" value="sendMail" />
	</bean>
	<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
	 	<property name="jobDetail" ref="jobDetail" />
	 	<property name="cronExpression" value="10 0/1 * * * ?" />
	</bean>
	<!-- 汇报考勤统计定时提醒邮件(本次总结的定时任务配置) -->
	<bean id="noteMailController" class="com.voole.smarteam.web.background.controller.NoteMailController"/>
	<bean id="noteMailDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject" ref="noteMailController" />
	 	<property name="targetMethod" value="sendNoteMail" />
	</bean>
	<bean id="noteMailCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
	 	<property name="jobDetail" ref="noteMailDetail" />
	 	<property name="cronExpression" value="0 0 9 ? * MON,FRI" /> <!-- 每周一和周五的九点执行 -->
	</bean>
	<!--  -->
	
	<bean id="taskTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
		 <property name="jobDetail" ref="jobDetail" />
		 <property name="startDelay" value="10000" />
		 <property name="repeatInterval" value="60000" />
	</bean>
	
	<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		 <property name="triggers">
			  <list>
			   		<ref bean="cronTrigger" />
			   		<ref bean="noteMailCronTrigger" />
			  </list>
		 </property>
		 <property name="taskExecutor" ref="executor" />
	</bean>
	


</beans>

总结:

主要是用要spring的定时邮件功能。

参考:

利用spring定时器发送定时邮件

Spring设置定时任务时,关于执行时间的规则设置

Spring+Quartz配置定时任务

猜你喜欢

转载自blog.csdn.net/zhufengyan521521/article/details/80351225