Jedis实现手机号验证码
要求
1.输入手机号,点击发送后随机生成6位数字码,2分钟有效
2.输入验证码,点击验证,返回成功或失败
3.每个手机号每天只能输入3次
创建线程有三种方式,分别是继承Thread类、实现Runnable接口、实现Callable接口。
1.通过继承Thread类来创建并启动线程的步骤如下:
1.1定义Thread类的子类,并重写该类的run()方法,该run()方法将作为线程执行体。
1.2创建Thread子类的实例,即创建了线程对象。
1.3调用线程对象的start()方法来启动该线程。
2.通过实现Runnable接口来创建并启动线程的步骤如下:
2.1定义Runnable接口的实现类,并实现该接口的run()方法,该run()方法将作为线程执行体。
2.2创建Runnable实现类的实例,并将其作为Thread的target来创建Thread对象,Thread对象为线程对象。
2.3调用线程对象的start()方法来启动该线程。
3.通过实现Callable接口来创建并启动线程的步骤如下:
3.1创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法有返回值。然后再创建Callable实现类的实例。
3.2使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
3.3使用FutureTask对象作为Thread对象的target创建并启动新线程。
3.4调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolCreationTest {
public static void fixedThreadPool(){
// ExecutorService threadPool = Executors.newFixedThreadPool(2);
//
// Runnable runnable = new Runnable(){
// @Override
// public void run(){
// System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
// }
// };
//
// Future<?> submit = threadPool.submit(runnable);
//// System.out.println(submit);
//// System.out.println(submit.isDone());
// threadPool.execute(runnable);
// threadPool.execute(runnable);
// threadPool.execute(runnable);
ExecutorService threadPool = Executors.newFixedThreadPool(2);
for(int i = 0; i < 4; i++){
threadPool.execute(() -> {
System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
});
}
}
public static void cachedThreadPool(){
ExecutorService threadPool = Executors.newCachedThreadPool();
for(int i=0;i<10;i++){
threadPool.execute(() -> {
System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
});
}
}
public static void singleThreadPool(){
ExecutorService threadPool = Executors.newSingleThreadExecutor();
for(int i = 0; i < 10; i++){
threadPool.execute(() -> {
System.out.println("任务被执行,线程:" + Thread.currentThread().getName());
});
}
}
public static void scheduledThreadPool(){
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);
System.out.println("添加任务,时间:"+new Date());
threadPool.schedule(()->{
System.out.println("任务被执行,时间:"+new Date());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 1, TimeUnit.SECONDS);
}
public static void singleThreadScheduledPool(){
ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
System.out.println("添加任务,时间:"+new Date());
threadPool.schedule(()->{
System.out.println("任务被执行,时间:"+new Date());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 2, TimeUnit.SECONDS);
}
public static void workStealingPool(){
ExecutorService threadPool = Executors.newWorkStealingPool();
for(int i = 0; i < 10; i++){
final int index = i;
threadPool.execute(() ->{
System.out.println(index + "被执行,线程名"+Thread.currentThread().getName());
});
}
while(!threadPool.isTerminated()){
}
}
//推荐使用
//阿里巴巴开发手册:线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
public static void myThreadPoolExecutor(){
final int CORE_POOL_SIZE = 5;
final int MAX_POOL_SIZE = 10;
final int QUEUE_CAPACITY = 100;
final Long KEEP_ALIVE_TIME = 1L;
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
new ThreadPoolExecutor.CallerRunsPolicy()
);
for(int i = 0; i < 10; i++){
final int index = i;
threadPool.execute(() -> {
System.out.println(index+"被执行,线程名:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
public static void main(String[] args) {
//fixedThreadPool();
//cachedThreadPool();
//singleThreadPool();
//scheduledThreadPool();
//singleThreadScheduledPool();
//workStealingPool();
myThreadPoolExecutor();
}
}
ThreadLocal:
通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢? JDK 中提供的ThreadLocal类正是为了解决这样的问题。
ThreadLocal类主要解决的就是让每个线程绑定自己的值,可以将ThreadLocal类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。
如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是ThreadLocal变量名的由来。他们可以使用 get() 和 set() 方法来获取默认值或将修改其值,从而避免了线程安全问题。
代码:
import java.text.SimpleDateFormat;
import java.util.Random;
public class ThreadLocalTest implements Runnable{
//private static final ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(()->new SimpleDateFormat("yyyyMMdd HHmm"));
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue(){
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
@Override
public void run() {
System.out.println("Thread Name="+Thread.currentThread().getName()+" default formatter="+formatter.get().toPattern());
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
formatter.set(new SimpleDateFormat());
System.out.println("Thread Name="+Thread.currentThread().getName()+" current formatter="+formatter.get().toPattern());
}
public static void main(String[] args) throws InterruptedException{
ThreadLocalTest obj = new ThreadLocalTest();
for(int i=0;i<10;i++){
Thread t = new Thread(obj, ""+i);
Thread.sleep(new Random().nextInt(1000));
t.start();
}
}
}
package SingletonTest;
class Singleton{
private volatile static Singleton instance;
private Singleton(){
}
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class) {
if(instance == null){
instance = new Singleton();
}
//instance = new Singleton();
}
}
return instance;
}
}
public class MyThread extends Thread{
@Override
public void run(){
System.out.println(Singleton.getInstance().hashCode());
}
public static void main(String[] args){
MyThread[] myThread = new MyThread[10];
for(int i=0;i<myThread.length;i++){
myThread[i] = new MyThread();
}
for(int i=0;i<myThread.length;i++){
myThread[i].start();
}
}
}
双重锁的运行结果:
1156205522
1156205522
1156205522
1156205522
1156205522
1156205522
1156205522
1156205522
1156205522
1156205522
去掉第二重锁的运行结果(产生了多例):
1700548907
1486202908
1486202908
1700548907
1486202908
1486202908
1700548907
1486202908
1486202908
1700548907
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public class HashMapTraversalMethodsTest {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap();
map.put(1, "Java");
map.put(2, "Python");
map.put(3, "C");
map.put(4, "C++");
map.put(5, "JavaScript");
//迭代器EntrySet(推荐使用)
// Iterator<Entry<Integer, String>> iterator = map.entrySet().iterator();
// while(iterator.hasNext()){
// Entry<Integer, String> entry = iterator.next();
// System.out.println(entry.getKey());
// System.out.println(entry.getValue());
// }
//迭代器KeySet
// Iterator<Integer> iterator = map.keySet().iterator();
// while(iterator.hasNext()){
// Integer key = iterator.next();
// System.out.println(key);
// System.out.println(map.get(key));
// }
//ForEach EntrySet
// for(Entry<Integer, String> entry:map.entrySet()){
// System.out.println(entry.getKey());
// System.out.println(entry.getValue());
// }
//ForEach KeySet
// for(Integer key:map.keySet()){
// System.out.println(key);
// System.out.println(map.get(key));
// }
//Lambda
// map.forEach((key, value) -> {
// System.out.println(key);
// System.out.println(value);
// });
//Streams API单线程
// map.entrySet().stream().forEach((entry) -> {
// System.out.println(entry.getKey());
// System.out.println(entry.getValue());
// });
//Streams API多线程
map.entrySet().parallelStream().forEach((entry) ->{
System.out.println(entry.getKey());
System.out.println(entry.getValue());
});
}
}
1.list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>展示员工信息</title>
<link rel="stylesheet" href="${pageContext.servletContext.contextPath}/css/index_work.css"/>
<script type="text/javascript" src="${pageContext.servletContext.contextPath}/js/jquery-1.8.2.min.js"></script>
<script type="text/javascript">
$(function(){
$("#selectAll").click(function(){
$("[name='eid']").prop("checked", $(this).prop("checked"));
});
$("#deleteMore").click(function(){
$("form").attr("action", $(this).attr("href")).submit();
return false;//关闭默认跳转
});
});
</script>
</head>
<body>
<form method="post">
<input type="hidden" name="_method" value="DELETE"/>
<table>
<tr>
<th>
<input type="checkbox" id="selectAll">
</th>
<th>EID</th>
<th>ENAME</th>
<th>AGE</th>
<th>SEX</th>
<th>DEPARTMENTNAME</th>
<th>OPTIONS</th>
</tr>
<c:forEach items="${empList}" var="emp">
<tr>
<td>
<input type="checkbox" name="eid" value="${emp.eid}"/>
</td>
<td>${emp.eid}</td>
<td>${emp.ename}</td>
<td>${emp.age}</td>
<td>${emp.sex == 0 ? '女':'男'}</td>
<td>${emp.dept.dname}</td>
<td>
<a href="emp">删除</a>
<a href="${pageContext.servletContext.contextPath}/emp/${emp.eid}">修改</a>
</td>
</tr>
</c:forEach>
<tr>
<td colspan="10">
<a id="deleteMore" href="${pageContext.servletContext.contextPath}/emps">批量删除</a>
${page}
</td>
</tr>
</table>
</form>
</body>
</html>
2.EmpMapper.java
public interface EmpMapper {
//获取所有的员工信息
List<Emp> getAllEmp();
......
void deleteMore(String eids);
}
3.EmpMapper.xml
<!-- void deleteMore(String eids); -->
<delete id="deleteMore">
delete from emp where eid in (${value})
</delete>
4.EmpService.java
public interface EmpService {
......
void deleteMore(String eids);
}
5.EmpServiceImpl.java
@Service
public class EmpServiceImpl implements EmpService{
@Autowired
private EmpMapper empMapper;
......
@Override
public void deleteMore(String eids) {
// TODO Auto-generated method stub
empMapper.deleteMore(eids);
}
}
6.EmpController.java
@Controller
public class EmpController {
@Autowired
private EmpService service;
......
@RequestMapping(value="/emps", method=RequestMethod.DELETE)
public String deleteMore(String eid){
//获取客户端name属性相同的多个元素的值,可以通过字符串直接获取,每个值以逗号分隔,也可以以数组直接获取
System.out.println(eid);
service.deleteMore(eid);
return "redirect:/emps/1";
}
}
1.list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>展示员工信息</title>
<link rel="stylesheet" href="${pageContext.servletContext.contextPath}/css/index_work.css"/>
</head>
<body>
<table>
<tr>
<th>EID</th>
<th>ENAME</th>
<th>AGE</th>
<th>SEX</th>
<th>DEPARTMENTNAME</th>
<th>OPTIONS</th>
</tr>
<c:forEach items="${empList}" var="emp">
<tr>
<td>${emp.eid}</td>
<td>${emp.ename}</td>
<td>${emp.age}</td>
<td>${emp.sex == 0 ? '女':'男'}</td>
<td>${emp.dept.dname}</td>
<td>
<a href="emp">删除</a>
<a href="${pageContext.servletContext.contextPath}/emp/${emp.eid}">修改</a>
</td>
</tr>
</c:forEach>
<tr>
<td colspan="10">
${page}
</td>
</tr>
</table>
</body>
</html>
2.update.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>修改员工信息</title>
<link rel="stylesheet" href="${pageContext.servletContext.contextPath}/css/index_work.css"/>
</head>
<body>
<form:form action="${pageContext.servletContext.contextPath}/emp" method="post" modelAttribute="emp">
<input type="hidden" name="_method" value="PUT"/>
<form:hidden path="eid"/>
<table>
<tr>
<th colspan="2">UPDATE EMP INFO</th>
</tr>
<tr>
<td>ENAME</td>
<td>
<form:input path="ename"/>
</td>
</tr>
<tr>
<td>AGE</td>
<td>
<form:input path="age"/>
</td>
</tr>
<tr>
<td>sex</td>
<td>
<form:radiobuttons path="sex" items="${sex}"/>
</td>
</tr>
<tr>
<td>DEPARTMENT</td>
<td>
<form:select path="dept.did" items="${deptList}" itemLabel="dname" itemValue="did"></form:select>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="修改" />
</td>
</tr>
</table>
</form:form>
</body>
</html>
3.EmpController.java
@Controller
public class EmpController {
@Autowired
private EmpService service;
@RequestMapping(value="/emp/{eid}", method=RequestMethod.GET)
public String toUpdate(@PathVariable("eid")String eid, Map<String, Object> map){
//要修改的员工信息
Emp emp = service.getEmpByEid(eid);
//所有的部门信息
List<Dept> deptList = service.getAllDept();
//获取存储性别的map集合
Map<String, String> sex = new HashMap<>();
sex.put("0", "女");
sex.put("1", "男");
map.put("emp", emp);
map.put("deptList", deptList);
map.put("sex", sex);
return "update";
}
@RequestMapping(value="/emp", method=RequestMethod.PUT)
public String updateEmp(Emp emp){
service.updateEmp(emp);
return "redirect:/emps/1";
}
}
4.EmpService.java
public interface EmpService {
......
List<Dept> getAllDept();
}
5.EmpServiceImpl.java
@Service
public class EmpServiceImpl implements EmpService{
@Autowired
private EmpMapper empMapper;
@Autowired
private DeptMapper deptMapper;
......
@Override
public List<Dept> getAllDept() {
// TODO Auto-generated method stub
return deptMapper.getAllDept();
}
}
1.导入jar包
spring:
springMVC:
mybatis:
第三方支持:log4j,pageHelper,AspectJ,jackson,jstl
2.搭建springMVC
(1)web.xml
CharacterEncodingFilter:filter
HiddenHttpMethodFilter:filter
DispatcherServlet:servlet
(2)springMVC.xml
扫描控制层组件:context:component-scan
视图解析器:InternalResourceViewResolver
Default Servlet:mvc:default-servlet-handler/
MVC驱动:<mvc:annotation-driven />
可选:MultipartResolver,拦截器