定时发送邮件,基于SSM
- 依赖导入
- 配置文件
- 目录结构
- applicationContext-dao.xml
- applicationContext-service.xml
- applicaitonContext-task.xml
- database.properties
- env.properties
- log4j.properties
- mybatis.xml
- spring-shiro.xml
- springmvc.xml
- webapp->WEB-INF->web.xml
- Test方法
- com.qf.SsmConstant
- com.qf.controller.ItemController
- com.qf.UserController
- com.qf.Handler.MyExceptionHandler
- com.qf.inerceptor.AuthenticationInterceptor
- com.qf.mapper.ItemMapper
- com.qf.mapper.UserMapper
- com.qf.pojo.Item
- com.qf.pojo.User
- com.qf.quartz.MyJobDetail
- com.qf.quartz.SendMailTask
- com.qf.quartz.SendMailUtil
- com.qf.realm.CustomRealm
- com.qf.service.ItemService
- com.qf.service.UserService
- com.qf.impl.ItemServiceImpl
- com.qf.service.impl.UserServiceImpl
- com.qf.test.CreateMail
- com.qf.util.PageInfo
- com.qf.util.SendSMSUtil
- com.qf.vo.ResultVO
- resources.mapper.ItemMapper
- resources.mapper.UserMapper
- SpringBoot中slf4j的使用jxc
- Exception的使用,jxc-SpringBoot
- 数据存到Redis-jxc
依赖导入
<?xml version="1.0" encoding="UTF-8"?>< project xmlns=“http://maven.apache.org/POM/4.0.0”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”>
< modelVersion>4.0.0< /modelVersion>
<groupId>com.qf</groupId>
<artifactId>day06-ssm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<!--声明版本号-->
<properties>
<spring.version>4.3.8.RELEASE</spring.version>
</properties>
<dependencies>
<!--1. mybatis.-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--2. mysql驱动.-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!--3. druid连接池.-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--4. lombok.-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
<!--5. mybatis-spring.-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--6. spring的核心依赖.-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--7. spring的aspects.-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!--8. spring的jdbc.-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--9. spring的test.-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!--10. junit.-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--11. log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--12. spring的webmvc.-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--13. servlet全家桶.-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--jackson依赖,用于处理json数据-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<!--云片短信平台SDK工具-->
<dependency>
<groupId>com.yunpian.sdk</groupId>
<artifactId>yunpian-java-sdk</artifactId>
<version>1.2.7</version>
</dependency>
<!--hibernate-validator校验-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
<!--shiro ,只用MD5加密功能-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<!--上传图片需要的两个依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--commons-lang3 工具类-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<!-- shiro整合spring全家桶-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!--quartz定时任务-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<!-- spring的支持包.-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- javamail-->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>
配置文件
目录结构
main->java|resources->mapper,applicaitonContext-dao.xml,application-service.xml,applicationContext-task.xml,database.properties,env.properties,log4j.properties,mybatis-config.xml,spring-shiro.xml,springmvc.xml
main->webapp->static|WEB-INF->jsp->web.xml
applicationContext-dao.xml
<?xml version="1.0" encoding="UTF-8"?>< beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:context=“http://www.springframework.org/schema/context”
xsi:schemaLocation=“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”>
<!--1. 加载properties文件-->
<context:property-placeholder location="classpath:database.properties" />
<!--2. 创建数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" >
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!--3. 创建 SqlSessionFactoryBean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!--1. 注入数据源-->
<property name="dataSource" ref="dataSource" />
<!--2. 加载mybatis核心配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml" />
<!--3. 扫描映射文件-->
<property name="mapperLocations" value="classpath:mapper/*.xml" />
<!--4. 配置别名-->
<property name="typeAliasesPackage" value="com.qf.pojo" />
</bean>
<!--4. 通过MapperScannerConfigurer扫描mapper接口-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定扫描的包-->
<property name="basePackage" value="com.qf.mapper" />
</bean>
</beans>
applicationContext-service.xml
<?xml version="1.0" encoding="UTF-8"?>< beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:tx=“http://www.springframework.org/schema/tx”
xmlns:context=“http://www.springframework.org/schema/context”
xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd”>
<!--开启IOC/DI的注解扫描-->
<context:component-scan base-package="com.qf.service.impl" />
<!--声明式事务-->
<!--1. 数据源事务管理器.-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入dataSource-->
<property name="dataSource" ref="dataSource" />
</bean>
<!--2. 开启事务注解扫描.-->
<tx:annotation-driven transaction-manager="transactionManager" />
< /beans>
applicaitonContext-task.xml
<?xml version="1.0" encoding="UTF-8"?>< beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd”>
<bean class="com.qf.quartz.SendMailUtil" />
<!-- 1. 具体任务-->
<bean id="heiheihei" class="com.qf.quartz.MyJobDetail" />
<!-- 2. 将任务设置到MethodInvokingJobDetailFactoryBean.-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!-- 1. 设置任务所在的类.-->
<property name="targetObject" ref="heiheihei" />
<!-- 2. 设置类中的方法作为任务.-->
<property name="targetMethod" value="say" />
</bean>
<!-- 3. 指定这个任务的执行周期 CronTriggerFactoryBean-->
<bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 1. 将任务描述设置进来.-->
<property name="jobDetail" ref="jobDetail" />
<!-- 2. 配置cron表达式指定任务的执行周期 从0秒开始,没3秒执行一次. -->
<property name="cronExpression" value="0/3 * * ? * *" />
</bean>
<!-- 1. 创建发送邮件实例-->
<bean id="sendBirthdayMail" class="com.qf.quartz.SendMailTask" />
<!-- 2. 配置到methodInvokingJob....-->
<bean id="sendBirthdayMailJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="sendBirthdayMail" />
<property name="targetMethod" value="sendBirthdayMail" />
</bean>
<!-- 3. 配置到cronTrigger...-->
<bean id="sendBirthdayMailTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="sendBirthdayMailJobDetail" />
<property name="cronExpression" value="30 15 17 * * ?" />
</bean>
<!-- 4. 将指定好周期的任务配置到课程表中 SchedulerFactoryBean-->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 设置trigger-->
<property name="triggers">
<array>
<ref bean="trigger" />
<ref bean="sendBirthdayMailTrigger" />
</array>
</property>
</bean>
< /beans>
database.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///ssm?characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root
env.properties
apikey=bf4463a129d359b07d20130026da2d30
pic_types=jpg,png,gif
log4j.properties
log4j.rootLogger=ERROR,A1
log4j.logger.org.mybatis = DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>< !DOCTYPE configuration
PUBLIC “-//mybatis.org//DTD Config 3.0//EN”
“http://mybatis.org/dtd/mybatis-3-config.dtd”>
< configuration>
<settings>
<!-- 开启驼峰映射 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--<typeAliases>-->
<!--<package name="com.qf.pojo" />-->
<!--</typeAliases>-->
< /configuration>
spring-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>< beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xmlns:context=“http://www.springframework.org/schema/context”
xsi:schemaLocation=“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”>
<!-- 开启realm的注解扫描-->
<context:component-scan base-package="com.qf.realm" />
<!-- 安全管理器.-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 注入realm-->
<property name="realm" ref="customRealm" />
</bean>
<!-- id为shiroFilter的实例.ShiroFilterFactoryBean-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 注入安全管理器-->
<property name="securityManager" ref="securityManager" />
<!-- 设置登录页面路径-->
<property name="loginUrl" value="/login.html" />
<!-- 没有权限时,跳转的页面-->
<property name="unauthorizedUrl" value="/401.html" />
<!-- 配置过滤器链-->
<property name="filterChainDefinitions" >
<value>
/user/* = anon
/static/* = anon
/* = authc
</value>
</property>
</bean>
< /beans>
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>< beans xmlns=“http://www.springframework.org/schema/beans”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:mvc=“http://www.springframework.org/schema/mvc”
xmlns:context=“http://www.springframework.org/schema/context”
xsi:schemaLocation=“http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd”>
<!--加载env.properties文件-->
<context:property-placeholder location="classpath:env.properties" />
<!--开启注解扫描-->
<context:component-scan base-package="com.qf.controller,com.qf.util,com.qf.handler" />
<!--mvc注解驱动-->
<mvc:annotation-driven />
<!--视图解析器
/WEB-INF/jsp/user/register.jsp
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!--基于tomcat对静态资源放行-->
<!-- 基于服务器的方式 -->
<mvc:default-servlet-handler />
<!--基于springmvc手动放行-->
<!-- <mvc:resources mapping="/static/**" location="/static/" />-->
<!-- 配置文件上传项-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- <property name="maxUploadSize" value="5242880" />-->
</bean>
<!-- 拦截器 -->
<!-- <mvc:interceptors>-->
<!-- <mvc:interceptor>-->
<!-- <mvc:mapping path="/**" />-->
<!-- <mvc:exclude-mapping path="/user/**"/>-->
<!-- <bean class="com.qf.interceptor.AuthenticationInterceptor" />-->
<!-- </mvc:interceptor>-->
<!-- </mvc:interceptors>-->
< /beans>
webapp->WEB-INF->web.xml
<?xml version="1.0" encoding="UTF-8"?>< web-app xmlns=“http://xmlns.jcp.org/xml/ns/javaee”
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=“http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd”
version=“3.1”>
<!-- shiro整合spring的过滤器-->
<!-- <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>-->
<!-- 处理404-->
<error-page>
<error-code>404</error-code>
<location>/form.jsp</location>
</error-page>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
<!--2. 处理post请求中文乱码-->
<filter>
<filter-name>characterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 处理RESTful的put|delete|patch请求-->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--1. 前端控制器-->
<servlet>
<servlet-name>springMvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--3. spring提供的监听器,在项目初始化时,加载applicationContext-*.xml-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-*.xml</param-value>
</context-param>
<!-- ,classpath:spring-shiro.xml-->
< /web-app>
Test方法
AcTest文件
package com.qf;
import com.yunpian.sdk.YunpianClient;
import com.yunpian.sdk.model.Result;
import com.yunpian.sdk.model.SmsSingleSend;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Map;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
“classpath:applicationContext-dao.xml”,
“classpath:applicationContext-service.xml”
})
public class AcTests {
@Test
public void sendSMS(){
}
}
UserMapperTest
package com.qf.mapper;
import com.qf.AcTests;
import com.qf.pojo.User;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.Set;
import static org.junit.Assert.*;
public class UserMapperTest extends AcTests {
@Autowired
private UserMapper userMapper;
@Test
public void findCountByUsername() {
Integer count = userMapper.findCountByUsername("admin123");
System.err.println(count);
}
@Test
@Transactional
public void save(){
User user = new User();
user.setUsername("xxxxx");
user.setPassword("xxxxx");
user.setPhone("11111111111");
Integer count = userMapper.save(user);
assertEquals(new Integer(1),count);
}
@Test
public void findByUsername(){
User user = userMapper.findByUsername("admin");
System.err.println(user);
}
@Test
public void findTodayPassBirthdayUser(){
Set<User> userList = userMapper.findTodayPassBirthdayUser();
for (User user : userList) {
System.err.println(user);
}
}
}
UserServiceTest
package com.qf.service;
import com.qf.AcTests;
import com.qf.pojo.User;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.Set;
import static org.junit.Assert.*;
public class UserServiceTest extends AcTests {
@Autowired
private UserService userService;
@Test
public void checkUsername() {
Integer count = userService.checkUsername("admin");
System.out.println(count);
}
@Test
@Transactional
public void register(){
User user = new User();
user.setUsername("xxxxx");
user.setPassword("xxxxx");
user.setPhone("11111111111");
Integer count = userService.register(user);
assertEquals(new Integer(1),count);
}
@Test
public void login(){
User user = userService.login("admin", "admin");
System.out.println(new Md5Hash("admin",null,1024).toString());
System.err.println(user);
}
@Test
public void findToday(){
Set<User> userList = userService.findTodayPassBirthdayUser();
System.out.println(userList);
}
}
com.qf.SsmConstant
package com.qf.constant;
public interface SsmConstant {
/** 重定向 */
String REDIRECT = "redirect:";
/** 放在session域中验证码的key. */
String CODE = "code";
/** 放在session域中的用户信息 */
String USER = "user";
/** 跳转到注册页面的路径 */
String REGISTER_UI = "/user/register-ui";
/** 跳转到登录页面的路径 */
String LOGIN_UI = "/user/login-ui";
/** 跳转到添加页面 */
String ITEM_ADD_UI = "/item/add-ui";
}
com.qf.controller.ItemController
package com.qf.controller;
import static com.qf.constant.SsmConstant.;
import com.qf.pojo.Item;
import com.qf.service.ItemService;
import com.qf.util.PageInfo;
import com.qf.vo.ResultVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@Controller
@RequestMapping("/item")
public class ItemController {
@Autowired
private ItemService itemService;
// 商品的首页
/**
* 2. controller接收三个参数.
* name,非必传项.
* page,非必传项,设置一个默认值,默认值为1.
* size,非必传项,设置一个默认值,默认值为5.
* @param name
* @param page
* @param size
* @return
*/
@GetMapping("/list")
public String list(String name,
@RequestParam(value = "page",defaultValue = "1")Integer page,
@RequestParam(value = "size",defaultValue = "5")Integer size,
Model model){
//1. 调用service查询数据
PageInfo<Item> pageInfo = itemService.findItemByNameLikeAndLimit(name,page,size);
//2. controller将pageInfo放到request域中,将接收到的商品名称name也放到request域中.
model.addAttribute("pageInfo",pageInfo);
model.addAttribute("name",name);
//3. 转发页面
return "item/item_list";
}
// 跳转到添加商品页面
// /item/add-ui
@GetMapping("/add-ui")
public String addUI(String addInfo,Model model){
model.addAttribute("addInfo",addInfo);
return "item/item_add";
}
@Value("${pic_types}")
public String picType;
// 添加商品信息.
// Request URL: http://localhost/item/add
// Request Method: POST
@PostMapping("/add")
public String add(@Valid Item item, BindingResult bindingResult,
RedirectAttributes redirectAttributes,
MultipartFile picFile, HttpServletRequest req) throws IOException {
//=========================校验参数======================================
//===============================================================
if(bindingResult.hasErrors()){
// 获得具体信息
String msg = bindingResult.getFieldError().getDefaultMessage();
// 参数不合法
redirectAttributes.addAttribute("addInfo",msg);
return REDIRECT + ITEM_ADD_UI;
}
//========================图片上传=======================================
//===============================================================
// 1. 对图片的大小做校验. 要求图片小于5M. 5242880
long size = picFile.getSize();
if(size > 5242880L){
// 图片过大
redirectAttributes.addAttribute("addInfo","图片过大,要求小于5M");
return REDIRECT + ITEM_ADD_UI;
}
boolean flag = false;
// 2. 对图片的类型做校验. jpg. png. gif.
String[] types = picType.split(",");
for (String type : types) {
if(StringUtils.endsWithIgnoreCase(picFile.getOriginalFilename(),type)){
// 图片类型正确.
flag = true;
break;
}
}
if(!flag){
// 图片类型不正确
redirectAttributes.addAttribute("addInfo","图片类型不正确,要求" + picType);
return REDIRECT + ITEM_ADD_UI;
}
// 3. 校验图片是否损坏.
BufferedImage image = ImageIO.read(picFile.getInputStream());
if(image == null){
// 图片已经损坏
redirectAttributes.addAttribute("addInfo","图片已经损坏");
return REDIRECT + ITEM_ADD_UI;
}
//===========================将图片保存到本地===fastDFS=========================================
//1. 给图片起一个新名字
String prefix = UUID.randomUUID().toString();
String suffix = StringUtils.substringAfterLast(picFile.getOriginalFilename(),".");
String newName = prefix + "." + suffix;
//2. 将图片保存到本地
String path = req.getServletContext().getRealPath("") + "\\static\\img\\" + newName;
File file = new File(path);
// 健壮性判断.
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
picFile.transferTo(file);
//3. 封装图片的访问路径.
String pic = "http://localhost/static/img/" + newName;
//====================================保存商品信息==================================================================
//======================================================================================================
item.setPic(pic);
// 调用service保存商品信息.
Integer count = itemService.save(item);
// 判断count
if(count == 1) {
return REDIRECT + "/item/list";
}else{
// 添加商品信息失败
redirectAttributes.addAttribute("addInfo","添加商品信息失败!");
return REDIRECT + ITEM_ADD_UI;
}
}
// 根据id删除商品信息.
// Request URL: http://localhost/item/del/14
// Request Method: DELETE
@DeleteMapping("/del/{id}")
@ResponseBody
public ResultVO del(@PathVariable Long id){
//1. 调用service删除商品
Integer count = itemService.del(id);
//2. 根据结果给页面响应json
if(count == 1){
// 删除成功
return new ResultVO(0,"成功",null);
}else{
return new ResultVO(88,"删除商品失败",null);
}
}
}
com.qf.UserController
package com.qf.controller;
import static com.qf.constant.SsmConstant.;
import com.qf.pojo.User;
import com.qf.service.UserService;
import com.qf.util.SendSMSUtil;
import com.qf.vo.ResultVO;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 发短信工具类.
@Autowired
private SendSMSUtil sendSMSUtil;
// 跳转到注册页面
@GetMapping("/register-ui")
public String registerUI(){
// 转发到注册页面.
return "user/register";
}
// Request URL: http://localhost/user/check-username
// Request Method: POST
// {"username":"admin"} <json>
//1. json数据需要反序列化成pojo对象.
// jsonlib 比较古老的json工具. 第三方依赖过多. 当POJO类过于复杂时,序列化可能会出现问题.
// jackson spring默认使用的工具. 三个依赖. 当POJO类过于复杂时,序列化可能会出现问题.
// gson google的json工具. 一个依赖.
// jackson和gson和spring framework可以0配置整合.
// fastJSON 阿里巴巴的json工具. 一个依赖. 当POJO类过于复杂时,序列化可能会出现问题.
// fastJSON号称自己是最快的json工具.
// 页面发送json数据时,接收的数据类型 -> map,pojo类.
@PostMapping("/check-username")
@ResponseBody // 不走视图解析器,直接响应. 如果返回结果为Map/pojo类,自动序列化成json.
public ResultVO checkUsername(@RequestBody User user){
//1. 调用service,判断用户名是否可用.
Integer count = userService.checkUsername(user.getUsername());
//2. 使用ResultVO响应数据
return new ResultVO(0,"成功",count);
/*
使用Map响应
//2. 封装响应数据的Map
Map<String,Object> result = new HashMap<>();
result.put("code",0);
result.put("msg","成功");
result.put("data",count);
//3. 返回
return result;
*/
}
//发送短信
// Request URL: http://localhost/user/send-sms
// Request Method: POST
@PostMapping(value = "/send-sms",produces = "text/html;charset=utf-8")
@ResponseBody
public String sendSMS(@RequestParam String phone, HttpSession session){
//1. 调用工具发短信.
String result = sendSMSUtil.sendSMS(session, phone);
//2. 将result响应给ajax引擎.
return result;
}
// 执行注册
// Request URL: http://localhost/user/register
// Request Method: POST
@PostMapping("/register")
public String register(@Valid User user, BindingResult bindingResult, HttpServletRequest request, String registerCode, HttpSession session, RedirectAttributes redirectAttributes) throws UnsupportedEncodingException {
request.setCharacterEncoding("UTF-8");
String username = request.getParameter("username");
String contentType = request.getHeader("Content-Type");
String method = request.getMethod();
//1. 校验验证码.
/*if(!StringUtils.isEmpty(registerCode)){
// 验证码不为空,
String code = (int) session.getAttribute(CODE) + "";
if(!registerCode.equals(code)){
// 验证码不正确
redirectAttributes.addAttribute("registerInfo","验证码错误!");
return REDIRECT + REGISTER_UI;
}
}*/
//2. 校验参数是否合法.
if(bindingResult.hasErrors() || StringUtils.isEmpty(registerCode)){
// 参数不合法.
String msg = bindingResult.getFieldError().getDefaultMessage();
if(StringUtils.isEmpty(msg)){
msg = "验证码为必填项,岂能不填!";
}
redirectAttributes.addAttribute("registerInfo",msg);
return REDIRECT + REGISTER_UI;
}
//3. 调用service执行注册功能.
Integer count = userService.register(user);
//4. 根据service返回的结果跳转到指定页面.
if(count == 1){
// 注册成功.
return REDIRECT + LOGIN_UI;
}else{
// 注册失败
redirectAttributes.addAttribute("registerInfo","服务器爆炸了!!");
return REDIRECT + REGISTER_UI;
}
}
// 跳转到登录页面.
// GET http://localhost/user/login-ui
@GetMapping("/login-ui")
public String loginUI(){
// int i = 1 / 0;
return "user/login";
}
// 执行登录
// Request URL: http://localhost/user/login
// Request Method: POST
@PostMapping("/login")
@ResponseBody
public ResultVO login(String username,String password){
//1. 校验参数是否合法.
if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){
// 参数不合法.
return new ResultVO(1,"用户名和密码为必填项,岂能不填!",null);
}
//2. 调用service执行登录.
// User user = userService.login(username,password);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(new UsernamePasswordToken(username,password));
return new ResultVO(0,"成功",null);
} catch (AuthenticationException e) {
e.printStackTrace();
return new ResultVO(2,"用户名或密码错误!",null);
}
}
com.qf.Handler.MyExceptionHandler
package com.qf.handler;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
@Component
public class MyExceptionHandler {
@ExceptionHandler(Exception.class)
public String ex(Exception ex){
ex.printStackTrace();
return "error";
}
}
com.qf.inerceptor.AuthenticationInterceptor
package com.qf.interceptor;
import com.qf.constant.SsmConstant;
import com.qf.pojo.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 权限校验.
*/
public class AuthenticationInterceptor implements HandlerInterceptor {
// 前处理, 执行controller方法之前.
// 可以选择对请求进行拦截/放行
// return false -> 拦截. return true -> 放行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1. 获得session.
HttpSession session = request.getSession();
//2. 通过session获取用户信息
User user = (User) session.getAttribute(SsmConstant.USER);
//3. 判断是否为null.
if(user == null) {
//3.1 为null -> 用户未登陆. -> 跳转到登陆页面.-> return false;
response.sendRedirect(request.getContextPath() + "/user/login-ui");
return false;
}else {
//3.2 不为null -> return true;
return true;
}
}
// 执行完controller,返回ModelAndView之后执行.
// 拦截器的post处理中,修改ModelAndView
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
}
// 拦截器后处理, 响应数据之前.
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
com.qf.mapper.ItemMapper
package com.qf.mapper;
import com.qf.pojo.Item;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* item的dao层接口.
*/
public interface ItemMapper {
//1. 查询商品的总条数
Long findCountByName(@Param("name")String name);
//2. 分页查询商品的具体信息
List<Item> findItemByNameLikeAndLimit(@Param("name")String name,
@Param("offset")Integer offset,
@Param("size")Integer size);
//3. 添加商品
Integer save(Item item);
//4. 删除商品
Integer delById(@Param("id") Long id);
}
com.qf.mapper.UserMapper
package com.qf.mapper;
import com.qf.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.Set;
/**
* 映射user用户表的mapper接口
* create by 郑大仙丶
* 2019/7/15 10:55
*/
public interface UserMapper {
//1. 根据用户名查询数据条数
Integer findCountByUsername(@Param("username")String username);
//2. 添加用户信息
Integer save(User user);
//3. 根据用户名查询用户信息.
User findByUsername(@Param("username")String username);
//4. 查询今日过生日的用户
Set<User> findTodayPassBirthdayUser();
}
com.qf.pojo.Item
package com.qf.pojo;
import lombok.Data;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.Date;
/**
* 商品表对应的实体类
*/
@Data
public class Item {
//id
public Long id;
// 商品名称
@NotBlank(message = "商品名称为必填项,岂能为空!")
private String name;
// 商品价格
@NotNull(message = "商品价格为必填项,岂能为空!")
private BigDecimal price;
// 商品的生产日期.
@DateTimeFormat(pattern = "yyyy-MM-dd")
@NotNull(message = "商品的生产日期为必填项,岂能为空!")
private Date productionDate;
// 商品的描述
@NotBlank(message = "商品描述为必填项,岂能为空!")
private String description;
// 商品的图片
private String pic;
// 商品的创建时间
private Date created;
}
com.qf.pojo.User
package com.qf.pojo;
import lombok.Data;
import org.hibernate.validator.constraints.NotBlank;
import java.util.Date;
/**
* user表映射的实体类.
* create by 郑大仙丶
* 2019/7/15 14:32
*/
@Data
public class User {
private Long id;
@NotBlank(message = "用户名为必填项,岂能不填!")
private String username;
@NotBlank(message = "密码为必填项,岂能不填!")
private String password;
@NotBlank(message = "手机号为必填项,岂能不填!")
private String phone;
// 盐
private String salt;
private Date birthday;
private String email;
private Date created;
}
com.qf.quartz.MyJobDetail
package com.qf.quartz;
public class MyJobDetail {
public void say(){
System.out.println("嘿嘿嘿!!");
}
}
com.qf.quartz.SendMailTask
package com.qf.quartz;
import com.qf.pojo.User;
import com.qf.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Set;
public class SendMailTask {
private final String FROM = "zjw_2301211@126.com";
private final String FROM_PWD = "z123123";
@Autowired
private UserService userService;
@Autowired
private SendMailUtil sendMailUtil;
public void sendBirthdayMail() throws Exception {
//1. 调用service获取今日过生日的用户
Set<User> userList = userService.findTodayPassBirthdayUser();
//2. 判断是否有内容
if(userList != null && userList.size() > 0){
// 有过生日的用户.
for (User user : userList) {
String subject = "生日快乐!";
String content = "<h1 style='color:red;'>祝" + user.getUsername() + "生日快乐!!!!!</h1>";
sendMailUtil.sendMail(FROM,user.getEmail(),FROM_PWD,subject,content);
}
}
}
}
com.qf.quartz.SendMailUtil
package com.qf.quartz;
import org.junit.Test;
import org.springframework.stereotype.Component;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Date;
import java.util.Properties;
public class SendMailUtil {
// 创建邮件,
public MimeMessage createMail(Session session,String from,String to,String subject,String content) throws Exception {
/*//1. 创建Properties对象.发送邮件时的配置信息.
Properties props = new Properties();
//2. 创建会话对象. session.
Session session = Session.getInstance(props);*/
//3. 通过session创建邮件对象.
MimeMessage message = new MimeMessage(session);
//4. 设置发件人.
message.setFrom(new InternetAddress(from));
//5. 设置收件人(抄送人,密送人.)
message.setRecipients(Message.RecipientType.TO,to);
//6. 设置主题 subject.
message.setSubject(subject,"UTF-8");
//7. 设置邮件的内容 content.
message.setContent(content,"text/html;charset=UTF-8");
//8. 设置发送邮件的时间.
message.setSentDate(new Date());
//9. 保存邮件.
message.saveChanges();
return message;
}
/**
* 发送邮件
* @param from
* @param to
* @param fromPwd
* @param subject
* @param content
* @throws Exception
*/
public void sendMail(String from,String to,String fromPwd,String subject,String content) throws Exception {
//1. 创建Properties对象.
Properties props = new Properties();
//2. 设置发送邮件时的配置信息.
//2.1 设置发送邮件使用的协议. smtp - simple mail transfer protocol
props.setProperty("mail.transport.protocol","smtp");
//2.2 邮件邮件服务器的地址. smtp.126.com
props.setProperty("mail.smtp.host","smtp.126.com");
//2.3 开启权限校验 true
props.setProperty("mail.smtp.auth","true");
//3. 获取session会话对象.
Session session = Session.getInstance(props);
//4. 设置打印日志.
session.setDebug(true);
//5. 创建邮件.
MimeMessage message = this.createMail(session,from,to,subject,content);
//6. 获取发送邮件的transport对象.
Transport transport = session.getTransport();
//7. 设置连接邮箱服务器的用户名和授权码|独立密码
transport.connect(from,fromPwd);
//8. 发送邮件.
transport.sendMessage(message,message.getAllRecipients());
//9. 释放资源.
transport.close();
}
}
com.qf.realm.CustomRealm
package com.qf.realm;
import com.qf.pojo.User;
import com.qf.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
@Component
public class CustomRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
{
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("MD5");
matcher.setHashIterations(1024);
this.setCredentialsMatcher(matcher);
}
public static void main(String[] args) {
String pwd = new Md5Hash("123123","bb85248d-22e3-4017-a945-9187bc6963ab",1024).toString();
System.out.println(pwd);
// 123123:9c3b5c0672cd599ccf1019bddaa8089b
// 123123:bb85248d-22e3-4017-a945-9187bc6963ab:1024: 149647a7f1066c592385f19e2a37fbb4
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 1. 获取用户名.
String username = (String) token.getPrincipal();
// 2. 根据用户名查询密码.
User user = userService.findByUsername(username);
// User user = this.findByUsername(username);
// 3. 如果密码为null -> 抛出UnknowAccountException
if (user == null){
return null;
}
// 4.1 将用户名和查询到的密码封装到返回结果, Info中, 返回由更底层的代码做密码校验.
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),"CustomRealm");
// 4.1 设置盐
info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
// 5. 返回info.
return info;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//1. 获取用户名称.
String username = ((User) principals.getPrimaryPrincipal()).getUsername();
//2. 通过用户名称查询全部的角色信息.
Set<String> roles = userService.findRolesByUsername(username);
// Set<String> roles = this.findRolesByUsername(username);
//3. 通过角色信息查询到全部的权限信息.
Set<String> perms = userService.findPermissionsByRoles(roles);
// Set<String> perms = this.findPermsByRoles(roles);
//4. 封装返回结果info,角色信息和权限信息设置进去.
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roles);
info.setStringPermissions(perms);
//5. 返回
return info;
}
}
com.qf.service.ItemService
package com.qf.service;
import com.qf.pojo.Item;
import com.qf.util.PageInfo;
/**
* item的Service层接口
*/
public interface ItemService {
// 分页查询商品信息
PageInfo<Item> findItemByNameLikeAndLimit(String name, Integer page, Integer size);
// 添加商品
Integer save(Item item)
// 根据id删除商品
Integer del(Long id);
}
com.qf.service.UserService
package com.qf.service;
import com.qf.pojo.User;
import java.util.Set;
public interface UserService {
// 根据用户名查询是否可用
Integer checkUsername(String username);
// 注册功能
Integer register(User user);
// 执行登录
User login(String username, String password);
// 根据用户名查询用户信息
User findByUsername(String username);
// 根据用户名查询用户角色
Set<String> findRolesByUsername(String username);
// 根据角色信息查询权限信息
Set<String> findPermissionsByRoles(Set<String> roles);
// 查询今天过生日的用户
Set<User> findTodayPassBirthdayUser();
}
com.qf.impl.ItemServiceImpl
package com.qf.service.impl;
import com.qf.mapper.ItemMapper;
import com.qf.pojo.Item;
import com.qf.service.ItemService;
import com.qf.util.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* item的service实现类
*/
@Service
public class ItemServiceImpl implements ItemService {
@Autowired
private ItemMapper itemMapper;
@Override
public PageInfo<Item> findItemByNameLikeAndLimit(String name, Integer page, Integer size) {
//将PageInfo创建出来,并且封装list集合,再返回
//1. 查询数据总条数.
Long total = itemMapper.findCountByName(name);
//2. 创建pageInfo对象.
PageInfo<Item> pageInfo = new PageInfo<>(page,size,total);
//3. 查询商品信息list.
List<Item> list = itemMapper.findItemByNameLikeAndLimit(name, pageInfo.getOffset(), pageInfo.getSize());
//4. 将list集合set到PageInfo中.
pageInfo.setList(list);
//5. 返回
return pageInfo;
}
@Override
@Transactional
public Integer save(Item item) {
return itemMapper.save(item);
}
@Override
@Transactional
public Integer del(Long id) {
return itemMapper.delById(id);
}
}
com.qf.service.impl.UserServiceImpl
package com.qf.service.impl;
import com.qf.mapper.UserMapper;
import com.qf.pojo.User;
import com.qf.service.UserService;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Set;
import java.util.UUID;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public Integer checkUsername(String username) {
// 健壮性代码..
if(!StringUtils.isEmpty(username)){
username = username.trim();
}
Integer count = userMapper.findCountByUsername(username);
return count;
}
@Override
public Integer register(User user) {
//0. 生成盐
String salt = UUID.randomUUID().toString();
user.setSalt(salt);
//1. 对密码加密.
String newPwd = new Md5Hash(user.getPassword(),salt,1024).toString();
user.setPassword(newPwd);
//2. 调用mapper保存数据.
Integer count = userMapper.save(user);
//3. 返回信息
return count;
}
@Override
public User login(String username, String password) {
//1. 根据用户名查询用户信息.
User user = userMapper.findByUsername(username);
//2. 判断查询的结果是否为null.
if(user != null) {
//2.1 如果不为null -> 判断密码.
String newPwd = new Md5Hash(password,null,1024).toString();
//3. 如果密码正确,直接返回查询到user.
if(user.getPassword().equals(newPwd)){
// 登录成功,返回user对象
return user;
}
}
//4. 其他情况统一返回null.
return null;
}
@Override
public User findByUsername(String username) {
return userMapper.findByUsername(username);
}
@Override
public Set<String> findRolesByUsername(String username) {
return null;
}
@Override
public Set<String> findPermissionsByRoles(Set<String> roles) {
return null;
}
@Override
public Set<User> findTodayPassBirthdayUser() {
return userMapper.findTodayPassBirthdayUser();
}
}
com.qf.test.CreateMail
package com.qf.test;
import org.junit.Test;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Date;
import java.util.Properties;
public class CreateMail {
// 创建邮件,
public MimeMessage createMail(Session session) throws Exception {
/*//1. 创建Properties对象.发送邮件时的配置信息.
Properties props = new Properties();
//2. 创建会话对象. session.
Session session = Session.getInstance(props);*/
//3. 通过session创建邮件对象.
MimeMessage message = new MimeMessage(session);
//4. 设置发件人.
message.setFrom(new InternetAddress("zjw_2301211@126.com"));
//5. 设置收件人(抄送人,密送人.)
message.setRecipients(Message.RecipientType.TO,"402424668@qq.com");
//6. 设置主题 subject.
message.setSubject("测试邮件发送","UTF-8");
//7. 设置邮件的内容 content.
message.setContent("<h1>测试邮件发送</h1>","text/html;charset=UTF-8");
//8. 设置发送邮件的时间.
message.setSentDate(new Date());
//9. 保存邮件.
message.saveChanges();
return message;
}
// 发送邮件.
@Test
public void sendMail() throws Exception {
//1. 创建Properties对象.
Properties props = new Properties();
//2. 设置发送邮件时的配置信息.
//2.1 设置发送邮件使用的协议. smtp - simple mail transfer protocol
props.setProperty("mail.transport.protocol","smtp");
//2.2 邮件邮件服务器的地址. smtp.126.com
props.setProperty("mail.smtp.host","smtp.126.com");
//2.3 开启权限校验 true
props.setProperty("mail.smtp.auth","true");
//3. 获取session会话对象.
Session session = Session.getInstance(props);
//4. 设置打印日志.
session.setDebug(true);
//5. 创建邮件.
MimeMessage message = this.createMail(session);
//6. 获取发送邮件的transport对象.
Transport transport = session.getTransport();
//7. 设置连接邮箱服务器的用户名和授权码|独立密码
transport.connect("zjw_2301211@126.com","z123123");
//8. 发送邮件
transport.sendMessage(message,message.getAllRecipients());
//9. 释放资源.
transport.close();
}
// 发件人邮箱地址.
// 发件人授权码.
// 收件人邮箱地址.
// 邮件的主题.
// 邮件的内容
}
com.qf.util.PageInfo
package com.qf.util;
import lombok.Data;
import java.util.List;
@Data
public class PageInfo<T> {
// 商品信息和分页信息
// 当前页
private Integer page; // 已知
// 每页显示条数
private Integer size; // 已知
// 查询总条数.
private Long total; // 已知
// 计算总页数.
private Integer pages; // total % size == 0 ? total / size : total / size + 1;
// 计算起始索引.
private Integer offset; // (page - 1) * size;
// 商品信息
private List<T> list; // 查询得到.
// 0
public PageInfo(Integer page, Integer size, Long total) {
this.page = page <= 0 ? 1 : page;
this.size = size <= 0 ? 5 : size;
this.total = total < 0 ? 0 : total;
// 计算出pages和offset;
this.pages = (int) (this.total % this.size == 0 ? this.total / this.size : this.total / this.size + 1);
this.offset = (this.page - 1) * this.size;
}
}
com.qf.util.SendSMSUtil
package com.qf.util;
import static com.qf.constant.SsmConstant.*;
import com.qf.constant.SsmConstant;
import com.yunpian.sdk.YunpianClient;
import com.yunpian.sdk.model.Result;
import com.yunpian.sdk.model.SmsSingleSend;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpSession;
import java.util.Map;
@Component
public class SendSMSUtil {
@Value("${apikey}")
private String apikey;
public String sendSMS(HttpSession session,String phone){
//初始化clnt,使用单例方式
YunpianClient clnt = new YunpianClient(apikey).init();
// 生成6位随机数
int code = (int)((Math.random()*9+1)*100000);
// 将正确的验证码设置到session域中
session.setAttribute(CODE,code);
System.out.println(code);
//发送短信API
Map<String, String> param = clnt.newParam(2);
param.put(YunpianClient.MOBILE, phone);
param.put(YunpianClient.TEXT, "【云片网】您的验证码是" + code);
Result<SmsSingleSend> r = clnt.sms().single_send(param);
//获取返回结果,返回码:r.getCode(),返回码描述:r.getMsg(),API结果:r.getData(),其他说明:r.getDetail(),调用异常:r.getThrowable()
//账户:clnt.user().* 签名:clnt.sign().* 模版:clnt.tpl().* 短信:clnt.sms().* 语音:clnt.voice().* 流量:clnt.flow().* 隐私通话:clnt.call().*
//释放clnt
clnt.close();
return r.getMsg();
}
}
com.qf.vo.ResultVO
package com.qf.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResultVO {
private Integer code;
private String msg;
private Object data;
}
resources.mapper.ItemMapper
<?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.qf.mapper.ItemMapper">
<!-- //1. 查询商品的总条数-->
<!-- Long findCountByName(@Param("name")String name);-->
<select id="findCountByName" resultType="Long">
select count(1) from item
<where>
<if test="name != null and name != ''">
name like "%"#{name}"%"
</if>
</where>
</select>
<!-- //2. 分页查询商品的具体信息-->
<!-- List<Item> findItemByNameLikeAndLimit(@Param("name")String name,-->
<!-- @Param("offset")String offset,-->
<!-- @Param("size")String size);-->
<select id="findItemByNameLikeAndLimit" resultType="Item">
select * from item
<where>
<if test="name != null and name != ''">
name like "%"#{name}"%"
</if>
</where>
order by created desc
limit #{offset},#{size}
</select>
<!-- //3. 添加商品-->
<!-- Integer save(Item item);-->
<insert id="save" parameterType="Item">
insert into
item
(name,price,production_date,description,pic)
values
(#{name},#{price},#{productionDate},#{description},#{pic})
</insert>
<!-- //4. 删除商品-->
<!-- Integer delById(@Param("id") Long id);-->
<delete id="delById" >
delete from item where id = #{id}
</delete>
< /mapper>
resources.mapper.UserMapper
<?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.qf.mapper.UserMapper”>
<!--//1. 根据用户名查询数据条数-->
<!--Integer findCountByUsername(@Param("username")String username);-->
<select id="findCountByUsername" resultType="Integer">
select count(1) from user where username = #{username}
</select>
<!--//2. 添加用户信息-->
<!--Integer save(User user);-->
<insert id="save" parameterType="User">
insert into
user
(username,password,salt,phone)
values
(#{username},#{password},#{salt},#{phone})
</insert>
<!-- //3. 根据用户名查询用户信息.-->
<!-- User findByUsername(@Param("username")String username);-->
<select id="findByUsername" resultType="User">
select * from user where username = #{username}
</select>
<!-- //4. 查询今日过生日的用户-->
<!-- Set<User> findTodayPassBirthdayUser();-->
<select id="findTodayPassBirthdayUser" resultType="User" >
select * from user where DATE_FORMAT(now(),'%m%d') = DATE_FORMAT(birthday,'%m%d');
</select>
< /mapper>
SpringBoot中slf4j的使用jxc
pom.xml
< ?xml version=“1.0” encoding=“UTF-8”?>
< project xmlns=“http://maven.apache.org/POM/4.0.0” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd”>
< modelVersion>4.0.0</modelVersion>
< parent>
< groupId>org.springframework.boot</groupId>
< artifactId>spring-boot-starter-parent</artifactId>
< version>2.0.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.qf</groupId>
<artifactId>jxc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jxc</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<!--pagehelper-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.10</version>
</dependency>
<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
< /project>
logback-spring.xml
<?xml version="1.0" encoding="UTF-8" ?>< configuration>
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>
%d - %msg%n
</pattern>
</layout>
</appender>
<appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<encoder>
<pattern>
%msg%n
</pattern>
</encoder>
<!--滚动策略-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--路径-->
<fileNamePattern>D:logs/info.%d.log</fileNamePattern>
</rollingPolicy>
</appender>
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<encoder>
<pattern>
%msg%n
</pattern>
</encoder>
<!--滚动策略-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--路径-->
<fileNamePattern>D:logs/error.%d.log</fileNamePattern>
</rollingPolicy>
</appender>
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>
<root level="info">
<appender-ref ref="consoleLog" />
<appender-ref ref="fileInfoLog" />
<appender-ref ref="fileErrorLog" />
</root>
< /configuration>
SaleServiceImpl使用log
package com.qf.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qf.entity.Sale;
import com.qf.enums.JxcEnum;
import com.qf.exception.JxcException;
import com.qf.mapper.SaleMapper;
import com.qf.service.ProductService;
import com.qf.service.SaleService;
import com.qf.vo.PageVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
@Service
@Slf4j
public class SaleServiceImpl implements SaleService {
@Autowired
private SaleMapper saleMapper;
@Autowired
ProductService productService;
@Override
public PageVO<Sale> findAllByPage(Integer page, Integer size, Integer flag) {
PageHelper.startPage(page,size);
List<Sale> sales = saleMapper.findSaleByFlag(flag);
PageInfo<Sale> salePageInfo = new PageInfo<>(sales);
PageVO<Sale> salePageVO = new PageVO<>(salePageInfo.getPageNum(),salePageInfo.getPageSize(),salePageInfo.getTotal(),salePageInfo.getPages(),salePageInfo.getList());
return salePageVO;
}
@Override
@Transactional
public void save(Sale sale) {
productService.reduceStock(sale.getProductId(),sale.getQuantity());
BigDecimal price = sale.getPrice();
Integer quantity = sale.getQuantity();
BigDecimal multiply = price.multiply(new BigDecimal(quantity));
sale.setTotalPrice(multiply);
int i = saleMapper.insertSelective(sale);
if (i != 1){
log.error("[保存销售记录] 保存失败 sale = {}",sale);
throw new JxcException(JxcEnum.SALE_SAVE_ERROR);
}
}
}
Exception的使用,jxc-SpringBoot
com.enums.JxcEnum
package com.qf.enums;
import lombok.Getter;
@Getter
public enum JxcEnum {
PARAMETER_ERROR(1,"参数不合法"),
USERNAME_ERROR(2,"用户名错误"),
PASSWORD_ERROR(3,"密码错误"),
UNKNOWN_ERROR(4,"未知错误"),
USER_NOT_LOGIN(5,"用户未登录"),
STOCK_NOT_ENOUGH(6,"库存不足"),
REDUCE_STOCK_ERROR(7,"削减库存失败"),
PRODUCT_NOT_EXIST(8,"商品不存在"),
SALE_SAVE_ERROR(9,"保存失败"),
;
private Integer code;
private String msg;
JxcEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
}
com.exception.JxcException
package com.qf.exception;
import com.qf.enums.JxcEnum;
import lombok.Getter;
@Getter
public class JxcException extends RuntimeException{
private Integer code;
public JxcException(Integer code,String message){
super(message);
this.code = code;
}
public JxcException(JxcEnum jxcEnum){
super(jxcEnum.getMsg());
this.code = jxcEnum.getCode();
}
}
com.controller.UserController使用自定义Exception
package com.qf.controller;
import com.qf.entity.User;
import com.qf.enums.JxcEnum;
import com.qf.service.UserService;
import com.qf.util.R;
import com.qf.vo.ResultVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
@Slf4j
@CrossOrigin(allowCredentials = "true")
@Api(tags = "用户模块接口")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/login")
@ApiOperation(value = "用户登录接口")
@ApiImplicitParams({@ApiImplicitParam(name = "username",value = "请输入用户名",defaultValue = "lisi"),
@ApiImplicitParam(name = "password",value = "请输入密码",defaultValue = "aaa")})
public ResultVO login(String username, String password){
if (StringUtils.isEmpty(username)||StringUtils.isEmpty(password)){
log.info("[用户登录]参数不合法,username = {},password = {}",username,password);
return R.error(JxcEnum.PARAMETER_ERROR);
}
Subject subject = SecurityUtils.getSubject();
try {
subject.login(new UsernamePasswordToken(username,password));
} catch (UnknownAccountException e) {
e.printStackTrace();
return R.error(JxcEnum.USERNAME_ERROR);
}catch (IncorrectCredentialsException e){
e.printStackTrace();
return R.error(JxcEnum.PARAMETER_ERROR);
}catch (Exception e){
e.printStackTrace();
return R.error(JxcEnum.UNKNOWN_ERROR);
}
return R.ok();
}
@GetMapping("/info")
@ApiOperation(value = "获取登录用户真实姓名")
public ResultVO info(){
Subject subject = SecurityUtils.getSubject();
User user = (User)subject.getPrincipal();
if (user == null){
log.info("[获取真实姓名] 用户未登录!!!");
return R.error(JxcEnum.USER_NOT_LOGIN);
}
return R.ok(user.getRealname());
}
//public static void main(String[] args) {
// System.out.println(new Md5Hash("aaa",null,1024).toString());
//}
@PostMapping("/logout")
@ApiOperation("退出登录")
public ResultVO logout(){
Subject subject = SecurityUtils.getSubject();
try {
subject.logout();
} catch (Exception e) {
e.printStackTrace();
return R.error(JxcEnum.UNKNOWN_ERROR);
}
return R.ok();
}
}
数据存到Redis-jxc
com.dao.RedisCache
package com.qf.dao;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static com.qf.dao.RedisSessionDAO.*;
@Component
public class RedisCache<K,V> implements Cache<K,V> {
@Autowired
private RedisTemplate redisTemplate;
private final String SHIRO_CACHE_KEY = "shiro-cache-key:";
@Override
public V get(K k) throws CacheException {
System.out.println("从redis中查询权限信息");
//1.查询
V v = (V)redisTemplate.opsForValue().get(SHIRO_CACHE_KEY + k);
//2.重新设置生存时间
redisTemplate.expire(k,TIME_OUT, TimeUnit.MINUTES);
//3.返回
return v;
}
@Override
public V put(K k, V v) throws CacheException {
System.out.println("将权限信息放到redis中!");
//1.设置值-并设置生存时间
redisTemplate.opsForValue().set(SHIRO_CACHE_KEY + k,v,TIME_OUT,TimeUnit.MINUTES);
//2.返回v
return v;
}
@Override
public V remove(K k) throws CacheException {
return null;
}
@Override
public void clear() throws CacheException {
}
@Override
public int size() {
return 0;
}
@Override
public Set<K> keys() {
return null;
}
@Override
public Collection<V> values() {
return null;
}
}
RedisSessionDAO
package com.qf.dao;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public class RedisSessionDAO extends AbstractSessionDAO {
@Autowired
private RedisTemplate redisTemplate;
private final String SHIRO_KEY="shiro-sessison-key:";
public static final Long TIME_OUT = 10L;
//建立一个会话连接,存储到redis中
@Override
protected Serializable doCreate(Session session) {
System.out.println("用户创建了session");
//1.获取一个sessionId
Serializable sessionId = super.generateSessionId(session);
//2.将sessionId和session绑定到一起
super.assignSessionId(session,sessionId);
//3.将sessionId作为key,session作为value存储到redis中,并同时设置生存时间
String key = SHIRO_KEY +sessionId;
redisTemplate.opsForValue().set(key,session,TIME_OUT,TimeUnit.MINUTES);
//4.返回sessionId
return sessionId;
}
//获取session信息,去Redis中获取
@Override
protected Session doReadSession(Serializable serializable) {
System.out.println("用户读取了session");
//1.封装key
String key = SHIRO_KEY + serializable;
//2.去redis中查询session
Session session = (Session)redisTemplate.opsForValue().get(key);
//3.重新设置生存时间
redisTemplate.expire(key,TIME_OUT,TimeUnit.MINUTES);
//4.返回session
return session;
}
//修改用户信息
@Override
public void update(Session session) throws UnknownSessionException {
System.out.println("用户修改了session");
//1.根据session获取sessionId
Serializable id = session.getId();
String key = SHIRO_KEY + id;
redisTemplate.opsForValue().set(key,session,TIME_OUT,TimeUnit.MINUTES);
}
//退出登录,清空session
@Override
public void delete(Session session) {
System.out.println("用户清空了session");
Serializable id = session.getId();
String key = SHIRO_KEY + id;
redisTemplate.delete(key);
}
//获取存活的用户
@Override
public Collection<Session> getActiveSessions() {
System.out.println("全部session信息已经获取");
//1.封装pattern
String pattern = SHIRO_KEY + "*";
//2.声明返回结果集
Set<Session> sessionSet = new HashSet<>();
//3.通过keys查询全部存活的key
Set keys = redisTemplate.keys(pattern);
//4.遍历全部的key
for (Object key : keys) {
//通过key获取session,并添加到返回结果
Session session = (Session) redisTemplate.opsForValue().get(key);
sessionSet.add(session);
}
//5.返回结果集
return sessionSet;
}
}
RedisSessionManager
package com.qf.dao;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.session.mgt.WebSessionKey;
import javax.servlet.ServletRequest;
import java.io.Serializable;
public class RedisSessionManager extends DefaultWebSessionManager {
@Override
protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
//1.获取sessionId
Serializable sessionId = getSessionId(sessionKey);
if (sessionId == null){
return null;
}
//2.先去request域中查询.
WebSessionKey webSessionKey = (WebSessionKey) sessionKey;
ServletRequest request = webSessionKey.getServletRequest();
Session session = (Session)request.getAttribute(sessionId.toString());
//3.如果没有结果查询
if (session == null){
//去redis中查询retriveSessionFromDataSource
session = super.retrieveSessionFromDataSource(sessionId);
//将查询结果放到request域中
request.setAttribute(sessionId.toString(),session);
}
//4.返回session
return session;
}
}