我是使用qq邮箱去发送邮件的:要去qq邮箱申请授权码才能发送
在看上边资料的时候,发现邮件其实用freemarker来做模版会很不错(因为邮箱的只有少部分内容是变的),于是又去找freemarker与spring整合的资料:
http://blog.csdn.net/lpjishu/article/details/51902024
http://blog.csdn.net/u013111003/article/details/52118514
http://www.jb51.net/article/43200.htm
上诉的maven坐标:
<!-- Javamail与Spring-context-support support包也与freemarker整合 --> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>3.2.3.RELEASE</version> </dependency> <!--freemarker--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.18</version> <type>jar</type> <scope>compile</scope> </dependency>
首先构建出发送邮件的模版数据、然后使用JavaMail发送带HTML格式的数据就行了。
/** * 邮件服务类,提供发送邮件的功能 */ @Service public class EmailService { @Autowired private JavaMailSender mailSender; @Autowired private SimpleMailMessage simpleMailMessage; /** * 使用mimeMessage发送的HTML格式的邮件。 * @param user * @param content * @throws Exception */ public void sendEmail(User user, String content,String url) throws Exception { String returnText = createSendData(user, content,url); // TODO 问题是出在发送邮件很慢 6086ms,解析freemarker才60ms 待优化 MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8"); messageHelper.setFrom(simpleMailMessage.getFrom()); messageHelper.setSubject(simpleMailMessage.getSubject()); //接受人 messageHelper.setTo(user.getUserEmail()); //内容,是HTML格式 messageHelper.setText(returnText, true); mailSender.send(mimeMessage); } /** * 使用freemarker创建要发送的邮件内容 * @param user 封装了要发送邮件的信息 * @param content 发送的目的是什么(一个模版、多种邮件) * @param url 操作的地址路径是什么 * @return HTML页面的内容 * @throws Exception */ public String createSendData(User user, String content,String url) throws Exception { Map<String, Object> map = new HashMap(); map.put("nickName", user.getUserNickname()); map.put("content", content); map.put("url", url); map.put("encodeUrl", Base64Util.encodeData(url)); String returnText = new FreeMarkerUtils().returnText("email.ftl", map); return returnText; } }
freemarker在springmvc配置文件中的配置:
<!-- 同时开启json格式的支持 --> <mvc:annotation-driven></mvc:annotation-driven> <!-- 扫描所有的controller 但是不扫描service --> <context:component-scan base-package="zhongfucheng"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan> <!-- 配置Freemarker屬性文件路徑 --> <bean id="freemarkerConfiguration" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="location" value="classpath:freemarker.properties"/> </bean> <!-- 配置freeMarker模板加載地址 --> <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <!-- 視圖解析器會在/WEB-INF/ftl/路徑下掃描視圖文件 --> <property name="templateLoaderPath" value="/WEB-INF/ftl"/> <!-- 设置页面中文乱码问题 --> <property name="freemarkerSettings"> <props> <prop key="defaultEncoding">UTF-8</prop> </props> </property> <property name="freemarkerVariables"> <map> <entry key="xml_escape" value-ref="fmXmlEscape"/> </map> </property> </bean> <bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/> <!-- 配置freeMarker視圖解析器 --> <bean id="freemakerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/> <!-- 掃描路徑內所有以ftl結尾的文件 --> <property name="viewNames"> <array> <value>*.ftl</value> </array> </property> <!-- 设置相关属性 --> <property name="cache" value="true"/> <property name="contentType" value="text/html; charset=UTF-8"/> <property name="exposeRequestAttributes" value="true"/> <property name="exposeSessionAttributes" value="true"/> <property name="exposeSpringMacroHelpers" value="true"/> <property name="requestContextAttribute" value="request"/> <!-- 給視圖解析器配置優先級,你可以給之前jsp視圖解析器的值配為2 --> <property name="order" value="1"/> </bean> <!--通用视图解析器--> <bean id="viewResolverCommon" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass"> <value>org.springframework.web.servlet.view.InternalResourceView </value> </property> <property name="order" value="2"/> </bean>
在设置freemaker路径的时候发现自己对Java路径的相对路径、绝对路径、项目路径已有些混乱了。后来通过一篇资料又好好地整理一下:
http://www.cnblogs.com/franson-2016/p/5728280.html
- 我的总结:凡是以“/"开头的都代表绝对路径,在Controller里边"/"前面代表着http://localhost:8080/项目名
- 无论通过Servlet、还是API获取得到都是在本机上的路径。
很多时候我们的项目路径在不同机器上是不一样的。因此要做到更好的通用性,可以将其在配置文件中配置起来。
提供一个工具类提取它就行了:
/** * 根据key读取配置文件的内容 * */ public class ReadPropertiesUtil { public static String readProp(String key) { InputStream in = ReadPropertiesUtil.class.getClassLoader().getResourceAsStream("system.properties"); Properties prop = new Properties(); try { prop.load(in); } catch (IOException e) { e.printStackTrace(); } return prop.getProperty(key); } }
扯了这么一大堆,我们的邮件已经能够发出去了
url链接使用了base64进行编码了,其实没什么,就是为了装个逼而已..
maven坐标:
<!--base64编码解码--> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.6</version> </dependency>
base64工具类:
/** * base64的编码解码 */ public class Base64Util { private static final String UTF_8 = "UTF-8"; /** * 对给定的字符串进行base64解码操作 */ public static String decodeData(String inputData) { try { if (null == inputData) { return null; } return new String(Base64.decodeBase64(inputData.getBytes(UTF_8)), UTF_8); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } /** * 对给定的字符串进行base64加密操作 */ public static String encodeData(String inputData) { try { if (null == inputData) { return null; } return new String(Base64.encodeBase64(inputData.getBytes(UTF_8)), UTF_8); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } }
那么接下来就是点击连接激活账户了,修改一下激活码值就行了。从上边我们已经写到了:激活链接24小时内有效,如果超过了一天用户再点击激活码的时候,那么我们就认为它无效,把数据库的记录删除了,让他重新注册。
/** * 激活账户(实际上就是修改表字段的值) * * @param userId * @return * @throws Exception */ @RequestMapping("/activate.do") public String activate(String userId) throws Exception { User user = userService.selectByPrimaryKey(userId); String title = ""; String content = ""; String subject = ""; if (user != null) { //得到当前时间和邮件时间对比,24小时内 if (System.currentTimeMillis() - user.getTokenExptime().getTime() < 86400000) { user.setActiState(User.ACTIVATION_SUCCESSFUL); userService.updateByPrimaryKeySelective(user); title = "用户激活页面"; subject = "用户激活"; content = "恭喜您成功激活账户"; } else { title = "激活失败页面"; subject = "用户激活"; content = "激活链接已超时,请重新注册"; //删除记录已便用户再次注册 userService.deleteByPrimaryKey(userId); } } //根据模版生成页面,重定向到页面中 Map<String, Object> map = new HashedMap(); map.put("title", title); map.put("content", content); map.put("subject", subject); map.put("path", getProjectPath()); createCommonHtml("promptPages.ftl", "promptPages.html", map); return "redirect:/promptPages.html"; }
编写登陆模块是用了我比较多的时间的,因为用了首次用了Shiro框架来进行做验证。当时候学的时候并不是学得很深入,于是出现了很多bug,改了几天才把它捋顺了。
登陆页面
登陆页面和注册页面其实是非常类似的,具体的步骤都和注册页面差不多。只不过我在登陆页面中加入了一个验证码:该验证码是动态的gif,是我之前看github项目的时候发现的。觉得挺好看的就拿过来用了。要想使用它就要导入它的相关java类:
来源github项目:https://github.com/baichengzhou/SpringMVC-Mybatis-Shiro-redis-0.2
登陆后台
我引入了Shiro框架来帮我做认证…
maven坐标:
<!--Shiro与Spring整合--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.8.3</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <!--Shiro与ehcache整合--> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.3</version> </dependency>
首先来post一下我的基础shiro博文:
https://zhongfucheng.bitcron.com/category/shiro
想要在shiro认证之前能够校验验证码的话,那么就需要我们去自定义表单过滤器了。
/** * 自定义一个表单过滤器的目的就是认证流程由自己控制 */ public class UserFormAuthenticationFilter extends FormAuthenticationFilter { }
当时候我重写了onAccessDenied()方法,在认证之前去校验验证码的正确性,并且使用ajax来进行提示用户是否有错误信息: