物流BOS


项目导入

如果因为环境或者项目导入的困难,而不能成功跑起来,那是真的飞jr烦

尽管现在idea都很好的解决了相关的问题,但并不觉得这玩意就完全碾压eclipse

项目导入的问题,一定要一次性解决好,做好记录,不要因为这玩意占据太多时间

让该bos项目跑起来:

事先配好maven(这东西因为很多时候不能联网,最好把仓库拷到本地),jdk7,tomcat7,mysql,仓库(直接用这个E: epository_bos epository)

(eclipse)每次删除tomcat及Server项目,重新建,部署启动

https://github.com/ChenCurry/bos.git(GitHub提示有安全问题,对外不可见)


持久层代码抽取

/**
 * 持久层通用接口
 * @param <T>
 */
public interface IBaseDao<T> {
    public void save(T entity);
    public void delete(T entity);
    public void update(T entity);
    public T findById(Serializable id);
    public List<T> findAll();
}
/**
 * 持久层通用实现
 * @param <T>
 */
public class BaseDaoImpl<T> extends HibernateDaoSupport implements IBaseDao<T> {
    //代表的是某个实体的类型
    private Class<T> entityClass;
    
    @Resource//根据类型注入spring工厂中的会话工厂对象sessionFactory
    public void setMySessionFactory(SessionFactory sessionFactory){
        super.setSessionFactory(sessionFactory);
    }
    
    //在父类(BaseDaoImpl)的构造方法中动态获得entityClass
    public BaseDaoImpl() {
        ParameterizedType superclass = (ParameterizedType) this.getClass().getGenericSuperclass();
        //获得父类上声明的泛型数组
        Type[] actualTypeArguments = superclass.getActualTypeArguments();
        entityClass = (Class<T>) actualTypeArguments[0];
    }
    
    public void save(T entity) {
        this.getHibernateTemplate().save(entity);
    }
    
    public void delete(T entity) {
        this.getHibernateTemplate().delete(entity);
    }
    
    public void update(T entity) {
        this.getHibernateTemplate().update(entity);
    }

    public T findById(Serializable id) {
        return this.getHibernateTemplate().get(entityClass, id);
    }

    public List<T> findAll() {
        String hql = "FROM " + entityClass.getSimpleName();
        return (List<T>) this.getHibernateTemplate().find(hql);
    }
}

表现层代码抽取

/**
 * 表现层通用实现
 * @param <T>
 */
public class BaseAction<T> extends ActionSupport implements ModelDriven<T> {
    //模型对象
    private T model;
    public T getModel() {
        return model;
    }
    
    //在构造方法中动态获取实体类型,通过反射创建model对象
    public BaseAction() {
        ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
        //获得BaseAction上声明的泛型数组
        Type[] actualTypeArguments = genericSuperclass.getActualTypeArguments();
        Class<T> entityClass = (Class<T>) actualTypeArguments[0];
        //通过反射创建对象
        try {
            model = entityClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

拦截器实现

BOSLoginInterceptor.java

/**
 * BOS项目的工具类
 */
public class BOSUtils {
    //获取session对象
    public static HttpSession getSession(){
        return ServletActionContext.getRequest().getSession();
    }
    //获取登录用户对象
    public static User getLoginUser(){
        return (User) getSession().getAttribute("loginUser");
    }
}
/**
 * 自定义的拦截器,实现用户未登录自动跳转到登录页面*/
public class BOSLoginInterceptor extends MethodFilterInterceptor{
    //拦截方法
    protected String doIntercept(ActionInvocation invocation) throws Exception {
        //从session中获取用户对象
        User user = BOSUtils.getLoginUser();
        if(user == null){
            //没有登录,跳转到登录页面
            return "login";
        }
        //放行
        return invocation.invoke();
    }
}

struts.xml

<interceptors>
    <!-- 注册自定义拦截器 -->
    <interceptor name="bosLoginInterceptor" class="com.itheima.bos.web.interceptor.BOSLoginInterceptor">
        <!-- 指定哪些方法不需要拦截 -->
        <param name="excludeMethods">login</param>
    </interceptor>
    <!-- 定义拦截器栈 -->
    <interceptor-stack name="myStack">
        <interceptor-ref name="bosLoginInterceptor"></interceptor-ref>
        <interceptor-ref name="defaultStack"></interceptor-ref>
    </interceptor-stack>
</interceptors>
<default-interceptor-ref name="myStack"/>

<!-- 全局结果集定义 -->
<global-results>
    <result name="login">/login.jsp</result>
</global-results>

分页代码抽取

public class BaseDaoImpl<T> extends HibernateDaoSupport implements IBaseDao<T> {}

传递引用?

/**
 * 通用分页查询方法
 */
public void pageQuery(PageBean pageBean) {
    int currentPage = pageBean.getCurrentPage();
    int pageSize = pageBean.getPageSize();
    DetachedCriteria detachedCriteria = pageBean.getDetachedCriteria();
    
    //查询total---总数据量
    detachedCriteria.setProjection(Projections.rowCount());//指定hibernate框架发出sql的形式----》select count(*) from bc_staff;
    List<Long> countList = (List<Long>) this.getHibernateTemplate().findByCriteria(detachedCriteria);
    Long count = countList.get(0);
    pageBean.setTotal(count.intValue());
    
    //查询rows---当前页需要展示的数据集合
    detachedCriteria.setProjection(null);//指定hibernate框架发出sql的形式----》select * from bc_staff;
    int firstResult = (currentPage - 1) * pageSize;
    int maxResults = pageSize;
    List rows = this.getHibernateTemplate().findByCriteria(detachedCriteria, firstResult, maxResults);
    pageBean.setRows(rows);
}
//属性驱动,接收页面提交的分页参数
private int page;
private int rows;

/**
 * 分页查询方法
 * @throws IOException 
 */
public String pageQuery() throws IOException{
    PageBean pageBean = new PageBean();
    pageBean.setCurrentPage(page);
    pageBean.setPageSize(rows);
    //创建离线提交查询对象
    DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Staff.class);
    pageBean.setDetachedCriteria(detachedCriteria);
    staffService.pageQuery(pageBean);
    
    //使用json-lib将PageBean对象转为json,通过输出流写回页面中
    //JSONObject---将单一对象转为json
    //JSONArray----将数组或者集合对象转为json
    JsonConfig jsonConfig = new JsonConfig();
    //指定哪些属性不需要转json
    jsonConfig.setExcludes(new String[]{"currentPage","detachedCriteria","pageSize"});
    String json = JSONObject.fromObject(pageBean,jsonConfig).toString();
    ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
    ServletActionContext.getResponse().getWriter().print(json);
    return NONE;
}

另:该页面(取派员)增删改


WebService服务(apche CXF)

基于CXF开发crm服务(WebService服务端)

数据库crm_heima32

/*
Navicat MySQL Data Transfer

Source Server         : root
Source Server Version : 50022
Source Host           : localhost:3306
Source Database       : crm

Target Server Type    : MYSQL
Target Server Version : 50022
File Encoding         : 65001

Date: 2015-04-19 17:46:45
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `t_customer`
-- ----------------------------
DROP TABLE IF EXISTS `t_customer`;
CREATE TABLE `t_customer` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) default NULL,
  `station` varchar(255) default NULL,
  `telephone` varchar(255) default NULL,
  `address` varchar(255) default NULL,
  `decidedzone_id` varchar(255) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_customer
-- ----------------------------
INSERT INTO `t_customer` VALUES ('1', '张三', '百度', '13811111111', '北京市西城区长安街100号', null);
INSERT INTO `t_customer` VALUES ('2', '李四', '哇哈哈', '13822222222', '上海市虹桥区南京路250号', null);
INSERT INTO `t_customer` VALUES ('3', '王五', '搜狗', '13533333333', '天津市河北区中山路30号', null);
INSERT INTO `t_customer` VALUES ('4', '赵六', '联想', '18633333333', '石家庄市桥西区和平路10号', null);
INSERT INTO `t_customer` VALUES ('5', '小白', '测试空间', '18511111111', '内蒙古自治区呼和浩特市和平路100号', null);
INSERT INTO `t_customer` VALUES ('6', '小黑', '联想', '13722222222', '天津市南开区红旗路20号', null);
INSERT INTO `t_customer` VALUES ('7', '小花', '百度', '13733333333', '北京市东城区王府井大街20号', null);
INSERT INTO `t_customer` VALUES ('8', '小李', '长城', '13788888888', '北京市昌平区建材城西路100号', null);
t_customer.sql

导入项目https://github.com/ChenCurry/crm_heima32.git

启动,服务便已经存在;访问http://localhost:8080/crm_heima32/service查看服务

cmd:wsimport -s . http://192.168.1.8:8080/crm_heima32/service/customer?wsdl(生成客户端调用服务需要的代码)

将生成的代码拷到项目中,即可在业务代码中进行调用,如

public class App {
    public static void main(String[] args) {
        CustomerServiceImplService ss = new CustomerServiceImplService();
        ICustomerService proxy = ss.getCustomerServiceImplPort();
        List<Customer> list = proxy.findAll();
        for (Customer customer : list) {
            System.out.println(customer);
        }
    }
}

权限控制(apche shiro)

先引入一个小例子clone https://github.com/ChenCurry/privilegedemo.git,了解如何进行权限控制

常见的权限控制方式

URL拦截权限控制

方法注解权限控制

创建权限数据模型(准备整合shiro)

  • 权限表
  • 角色表
  • 用户表
  • 角色权限关系表
  • 用户角色关系表

角色就是权限的集合,引入角色表,是为了方便授权

PowerDesigner导出sql

整合到项目中

<!-- 引入shiro框架的依赖 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-all</artifactId>
    <version>1.2.2</version>
</dependency>

过滤器要放到web.xml中struts过滤器的前面

  <!-- 配置spring框架提供的用于整合shiro框架的过滤器 -->
  <filter>
      <filter-name>shiroFilter</filter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>shiroFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>

applicationContext.xml

<!-- 配置shiro框架的过滤器工厂对象 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <!-- 注入安全管理器对象 -->
    <property name="securityManager" ref="securityManager"/>
    <!-- 注入相关页面访问URL -->
    <property name="loginUrl" value="/login.jsp"/>
    <property name="successUrl" value="/index.jsp"/>
    <property name="unauthorizedUrl" value="/unauthorized.jsp"/>
    <!--注入URL拦截规则 -->
    <property name="filterChainDefinitions">
        <value>
            /css/** = anon
            /js/** = anon
            /images/** = anon
            /validatecode.jsp* = anon
            /login.jsp = anon
            /userAction_login.action = anon
            /page_base_staff.action = perms["staff-list"]
            /* = authc
        </value>
    </property>
</bean>

<!-- 注册安全管理器对象 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="bosRealm"/>
</bean>

<!-- 注册realm -->
<bean id="bosRealm" class="com.itheima.bos.realm.BOSRealm"></bean>

认证要交给shiro框架来做,不然永远会被拦截出来

/**
 * 用户登录,使用shiro框架提供的方式进行认证操作
 */
public String login(){
    //从Session中获取生成的验证码
    String validatecode = (String) ServletActionContext.getRequest().getSession().getAttribute("key");
    //校验验证码是否输入正确
    if(StringUtils.isNotBlank(checkcode) && checkcode.equals(validatecode)){
        //使用shiro框架提供的方式进行认证操作
        Subject subject = SecurityUtils.getSubject();//获得当前用户对象,状态为“未认证”
        AuthenticationToken token = new UsernamePasswordToken(model.getUsername(),MD5Utils.md5(model.getPassword()));//创建用户名密码令牌对象
        try{
            subject.login(token);
        }catch(Exception e){
            e.printStackTrace();
            return LOGIN;
        }
        User user = (User) subject.getPrincipal();
        ServletActionContext.getRequest().getSession().setAttribute("loginUser", user);
        return HOME;
    }else{
        //输入的验证码错误,设置提示信息,跳转到登录页面
        this.addActionError("输入的验证码错误!");
        return LOGIN;
    }
}

安全管理器(框架自己)调下面的对象

public class BOSRealm extends AuthorizingRealm{
    @Autowired
    private IUserDao userDao;
    
    //认证方法
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("自定义的realm中认证方法执行了。。。。");
        UsernamePasswordToken passwordToken = (UsernamePasswordToken)token;
        //获得页面输入的用户名
        String username = passwordToken.getUsername();
        //根据用户名查询数据库中的密码
        User user = userDao.findUserByUsername(username);
        if(user == null){
            //页面输入的用户名不存在
            return null;
        }
        //简单认证信息对象
        AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
        //框架负责比对数据库中的密码和页面输入的密码是否一致
        return info;
    }

    //授权方法
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }
}

在realm中进行授权

①url拦截(上面的方式)

②使用shiro的方法注解方式权限控制

<!-- 开启shiro框架注解支持 -->
<bean id="defaultAdvisorAutoProxyCreator" 
    class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
        <!-- 必须使用cglib方式为Action对象创建代理对象 -->
    <property name="proxyTargetClass" value="true"/>
</bean>

<!-- 配置shiro框架提供的切面类,用于创建代理对象 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"/>

action中用注解控制(主要工作量在这里边)

@Controller
@Scope("prototype")
public class StaffAction extends BaseAction<Staff>{
    @Autowired
    private IStaffService staffService;
    
    /**
     * 添加取派员
     */
    public String add(){
        staffService.save(model);
        return LIST;
    }
    
    /**
     * 分页查询方法
     * @throws IOException 
     */
    public String pageQuery() throws IOException{
        staffService.pageQuery(pageBean);
        this.java2Json(pageBean, new String[]{"decidedzones","currentPage","detachedCriteria","pageSize"});
        return NONE;
    }
    
    //属性驱动,接收页面提交的ids参数
    private String ids;
    
    /**
     * 取派员批量删除
     */
    @RequiresPermissions("staff-delete")//执行这个方法,需要当前用户具有staff-delete这个权限
    public String deleteBatch(){
        staffService.deleteBatch(ids);
        return LIST;
    }
    
    /**
     * 修改取派员信息
     */
    @RequiresPermissions("staff-edit")
    public String edit(){
        //Subject subject = SecurityUtils.getSubject();
        //subject.checkPermission("staff-edit");
        //显查询数据库,根据id查询原始数据
        Staff staff = staffService.findById(model.getId());
        //使用页面提交的数据进行覆盖
        staff.setName(model.getName());
        staff.setTelephone(model.getTelephone());
        staff.setHaspda(model.getHaspda());
        staff.setStandard(model.getStandard());
        staff.setStation(model.getStation());
        staffService.update(staff);
        return LIST;
    }
    
    /*public static void main(String[] args) {
        PageBean pageBean = new PageBean();
        pageBean.setCurrentPage(2);
        pageBean.setPageSize(30);
        String json = JSONObject.fromObject(pageBean ).toString();
        System.out.println(json);
    }*/

    /**
     * 查询所有未删除的取派员,返回json
     */
    public String listajax(){
        List<Staff> list = staffService.findListNotDelete();
        this.java2Json(list, new String[]{"decidedzones"});
        return NONE;
    }
    
    public String getIds() {
        return ids;
    }

    public void setIds(String ids) {
        this.ids = ids;
    }
}

struts.xml全局异常捕获

<!-- 全局结果集定义 -->
<global-results>
    <result name="login">/login.jsp</result>
    <result name="unauthorized">/unauthorized.jsp</result>
</global-results>

<global-exception-mappings>
    <exception-mapping result="unauthorized" 
        exception="org.apache.shiro.authz.UnauthorizedException"></exception-mapping>
</global-exception-mappings>

<!-- 需要进行权限控制的页面访问 -->
<action name="page_*_*">
    <result type="dispatcher">/WEB-INF/pages/{1}/{2}.jsp</result>
</action>
<!-- 用户管理 -->
<action name="userAction_*" class="userAction" method="{1}">
    <result name="home">/index.jsp</result>
</action>
<!-- 取派员管理 -->
<action name="staffAction_*" class="staffAction" method="{1}">
    <result name="list">/WEB-INF/pages/base/staff.jsp</result>
</action>
<!-- 区域管理 -->
<action name="regionAction_*" class="regionAction" method="{1}">
</action>
<!-- 分区管理 -->
<action name="subareaAction_*" class="subareaAction" method="{1}">
    <result name="list">/WEB-INF/pages/base/subarea.jsp</result>
</action>
<!-- 定区管理 -->
<action name="decidedzoneAction_*" class="decidedzoneAction" method="{1}">
    <result name="list">/WEB-INF/pages/base/decidedzone.jsp</result>
</action>
<!-- 业务通知单管理 -->
<action name="noticebillAction_*" class="noticebillAction" method="{1}">
    <result name="noticebill_add">/WEB-INF/pages/qupai/noticebill_add.jsp</result>
</action>
<!-- 工作单 管理 -->
<action name="workordermanageAction_*" class="workordermanageAction" method="{1}">
</action>
<!-- 权限管理 -->
<action name="functionAction_*" class="functionAction" method="{1}">
    <result name="list">/WEB-INF/pages/admin/function.jsp</result>
</action>
View Code

③使用页面标签方式权限控制

引入shiro标签库

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

使用shiro元素控制页面展示

④代码级别权限控制(基于代理技术实现)

初始化权限数据

权限控制整理完成,项目上线需要导入初始化权限数据

INSERT INTO `auth_function` VALUES ('11', '基础档案', 'jichudangan', null, null, '1', '0', null);
INSERT INTO `auth_function` VALUES ('112', '收派标准', 'standard', null, 'page_base_standard.action', '1', '1', '11');
INSERT INTO `auth_function` VALUES ('113', '取派员设置', 'staff', null, 'page_base_staff.action', '1', '2', '11');
INSERT INTO `auth_function` VALUES ('114', '区域设置', 'region', null, 'page_base_region.action', '1', '3', '11');
INSERT INTO `auth_function` VALUES ('115', '管理分区', 'subarea', null, 'page_base_subarea.action', '1', '4', '11');
INSERT INTO `auth_function` VALUES ('116', '管理定区/调度排班', 'decidedzone', null, 'page_base_decidedzone.action', '1', '5', '11');
INSERT INTO `auth_function` VALUES ('12', '受理', 'shouli', null, null, '1', '1', null);
INSERT INTO `auth_function` VALUES ('121', '业务受理', 'noticebill', null, 'page_qupai_noticebill_add.action', '1', '0', '12');
INSERT INTO `auth_function` VALUES ('122', '工作单快速录入', 'quickworkordermanage', null, 'page_qupai_quickworkorder.action', '1', '1', '12');
INSERT INTO `auth_function` VALUES ('124', '工作单导入', 'workordermanageimport', null, 'page_qupai_workorderimport.action', '1', '3', '12');
INSERT INTO `auth_function` VALUES ('13', '调度', 'diaodu', null, null, '1', '2', null);
INSERT INTO `auth_function` VALUES ('131', '查台转单', 'changestaff', null, null, '1', '0', '13');
INSERT INTO `auth_function` VALUES ('132', '人工调度', 'personalassign', null, 'page_qupai_diaodu.action', '1', '1', '13');
INSERT INTO `auth_function` VALUES ('14', '物流配送流程管理', 'zhongzhuan', null, null, '1', '3', null);
INSERT INTO `auth_function` VALUES ('141', '启动配送流程', 'start', null, 'workOrderManageAction_list.action', '1', '0', '14');
INSERT INTO `auth_function` VALUES ('142', '查看个人任务', 'personaltask', null, 'taskAction_findPersonalTask.action', '1', '1', '14');
INSERT INTO `auth_function` VALUES ('143', '查看我的组任务', 'grouptask', null, 'taskAction_findGroupTask.action', '1', '2', '14');
INSERT INTO `auth_function` VALUES ('8a7e843355a4392d0155a43aa7150000', '删除取派员', 'staff.delete', 'xxx', 'staffAction_delete.action', '0', '1', '113');
INSERT INTO `auth_function` VALUES ('8a7e843355a442460155a442bcfc0000', '传智播客', 'itcast', '', 'http://www.itcast.cn', '1', '1', null);
auth_function.sql

上线之后,再开发新的功能,分配新的权限,可在页面进行配置。

用ehcache缓存权限数据

也是属于shiro的一部分,用于缓存Java对象,注入到项目中即可用

<!-- 引入ehcache的依赖 -->
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache-core</artifactId>
    <version>2.6.6</version>
</dependency>

需要引入配置文件(用于设置缓存的规则)

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />
</ehcache>
ehcache.xml

applicationContext.xml中注入

<!-- 注册安全管理器对象 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="bosRealm"/>
    <!-- 注入缓存管理器 -->
    <property name="cacheManager" ref="cacheManager"/>
</bean>

<!-- 注册缓存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    <!-- 注入ehcache的配置文件 -->
    <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
</bean>

完了之后,就不会每次都进行BOSRealm类的授权方法了


任务调度Quartz

即定时任务,发邮件

http://www.quartz-scheduler.org/

<!-- 引入quartz对应的依赖 -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.3</version>
</dependency>
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.2.3</version>
</dependency>
<!-- 引入JavaMail的依赖 -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4</version>
</dependency>

创建任务类

/**
 * 发送邮件的作业
 */
public class MailJob {
    @Resource
    private IWorkbillDao workbillDao;
    private String username;//发件人的邮箱账号
    private String password;//密码
    private String smtpServer;//服务器
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void execute() {
        System.out.println("要发邮件了。。。" + new Date());
        try {
            //查询工单类型为新单的所有工单
            List<Workbill> list = workbillDao.findAll();
            if(null != list && list.size() > 0){
                final Properties mailProps = new Properties();
                mailProps.put("mail.smtp.host", this.getSmtpServer());
                mailProps.put("mail.smtp.auth", "true");
                mailProps.put("mail.username", this.getUsername());
                mailProps.put("mail.password", this.getPassword());

                // 构建授权信息,用于进行SMTP进行身份验证
                Authenticator authenticator = new Authenticator() {
                    protected PasswordAuthentication getPasswordAuthentication() {
                        // 用户名、密码
                        String userName = mailProps.getProperty("mail.username");
                        String password = mailProps.getProperty("mail.password");
                        return new PasswordAuthentication(userName, password);
                    }
                };
                // 使用环境属性和授权信息,创建邮件会话
                Session mailSession = Session.getInstance(mailProps, authenticator);
                for(Workbill workbill : list){
                    // 创建邮件消息
                    MimeMessage message = new MimeMessage(mailSession);
                    // 设置发件人
                    InternetAddress from = new InternetAddress(mailProps.getProperty("mail.username"));
                    message.setFrom(from);
                    // 设置收件人
                    InternetAddress to = new InternetAddress("test@itcast.cn");
                    message.setRecipient(RecipientType.TO, to);
                    // 设置邮件标题
                    message.setSubject("系统邮件:新单通知");
                    // 设置邮件的内容体
                    message.setContent(workbill.toString(), "text/html;charset=UTF-8");
                    // 发送邮件
                    Transport.send(message);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public String getSmtpServer() {
        return smtpServer;
    }

    public void setSmtpServer(String smtpServer) {
        this.smtpServer = smtpServer;
    }
}

注入到spring

<!-- 注册自定义作业类 -->
<bean id="myJob" class="com.itheima.jobs.MailJob">
    <property name="username" value="xxxx@126.com"/>
    <property name="password" value="xxxx"/>
    <property name="smtpServer" value="smtp.126.com"/>
</bean>

<!-- 配置JobDetail -->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <!-- 注入目标对象 -->
    <property name="targetObject" ref="myJob"/>
    <!-- 注入目标方法 -->
    <property name="targetMethod" value="execute"/>
</bean>

<!-- 配置触发器 -->
<bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <!-- 注入任务详情对象 -->
    <property name="jobDetail" ref="jobDetail"/>
    <!-- 注入cron表达式,通过这个表达式指定触发的时间点 -->
    <property name="cronExpression">
        <value>0/5 * * * * ?</value>
    </property>
</bean>

<!-- 配置调度工厂 -->
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <!-- 注入触发器 -->
    <property name="triggers">
        <list>
            <ref bean="myTrigger"/>
        </list>
    </property>
</bean>

自动表达式生成https://qqe2.com/cron


击石乃有火,不击元无烟!!
原文地址:https://www.cnblogs.com/rain2020/p/13148702.html