什么是springboot
springboot是spring组织生产的一个后端全栈框架(不包括页面的技术)
作用:
提倡零配置, 不用整合框架结构, 直接编写业务代码, 给企业提供人员利用率, 提高开发效率.
但是springboot只适合小项目使用.
springboot搭建消息中间键连接阿里大于
1.pom.xml 导入jar坐标:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.2.5</version>
</dependency>
2.指定springboot内置tomcat的相关参数,和阿里大于子账户的账户名id和密码
server.port=9003
spring.activemq.broker-url=tcp://192.168.200.128:61616
accessKeyId=LTAIYr97uNKHy2fm
accessKeySecret=tBY0x1YclGcfPIF0IaebZoDOA0UVid
3.搭建springboot微服务框架
启动类Application.java:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
监听器类SmsListener.java:
@Component
public class SmsListener {
@Autowired
private SmsUtil smsUtil;
@JmsListener(destination="sms")
public void sendSms(Map<String,String> map){
try {
SendSmsResponse response = smsUtil.sendSms(
map.get("mobile"),
map.get("template_code"),
map.get("sign_name"),
map.get("param") );
System.out.println("Code=" + response.getCode());
System.out.println("Message=" + response.getMessage());
System.out.println("RequestId=" + response.getRequestId());
System.out.println("BizId=" + response.getBizId());
} catch (ClientException e) {
e.printStackTrace();
}
}
}
信息提交给阿里大于的工具类:SmsUtil.java
@Component
public class SmsUtil {
//产品名称:云通信短信API产品,开发者无需替换
static final String product = "Dysmsapi";
//产品域名,开发者无需替换
static final String domain = "dysmsapi.aliyuncs.com";
@Autowired
private Environment env;
// TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
/**
* 发送短信
* @param mobile 手机号
* @param template_code 模板号
* @param sign_name 签名
* @param param 参数
* @return
* @throws ClientException
*/
public SendSmsResponse sendSms(String mobile,String template_code,String sign_name,String param) throws ClientException {
String accessKeyId =env.getProperty("accessKeyId");
String accessKeySecret = env.getProperty("accessKeySecret");
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号
request.setPhoneNumbers(mobile);
//必填:短信签名-可在短信控制台中找到
request.setSignName(sign_name);
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode(template_code);
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam(param);
//选填-上行短信扩展码(无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId("yourOutId");
//hint 此处可能会抛出异常,注意catch
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
return sendSmsResponse;
}
}
启动时先启动main方法。
阿里大于创建子账户,和相关参数的获取,视频参考:day58 视频
在互联网企业, 高并发, 大数据量的情况下, 单个数据库指定在一定情况下会造成数据库宕机. 数据库怎么做集群:
-
业务:
读大于写(大多数企业业务都这样)
数据库解决方案:
集群, 读写分离, 一台主库作为写入的数据库, 写数据库不允许读, 多台从库, 也就是读取库, 读取库
不允许人为的往里写数据. 平时高并发读的时候, 例如: a用户从一个库中去读取数据, b用户去另一个从库中
去读取数据, 这样高并发的读取操作就可以负载均衡了. -
业务:
写大于读(特殊业务)
数据库解决方案:
集群, 多个数据库, 多个数据库中存储的内容不一样, 但是多个数据库中不管是库名还是表名, 还是表结构都是
一模一样的, 只是存储的数据不一样而已, 这种配置叫做分库, 在数据量很大的情况下还需要分表,
同样的表结构的表有一堆, 每个表存储的内容也不一样, 也叫作水平分表, mysql最好单表的数据量保证在
五百万条以内, 那么查询效率不会太低, 如果超过这个数据量, 命中率会成指数级下降.
用户注册流程(图解)
1.写用户的控制器类UserController:
@RestController
@RequestMapping("/user")
public class UserController {
@Reference
private UserService userService;
/**
* 发送短信验证码
* @param phone 手机号
* @return
*/
@RequestMapping("/sendCode")
public Result sendCode(String phone){
//先判断进来的电话号码是否符合规格,判断非空,和正则工具类验证
boolean chinaPhoneLegal = PhoneFormatCheckUtils.isChinaPhoneLegal(phone);
if (!chinaPhoneLegal || "".equals(phone)||phone == null){
return new Result(false,"电话不符合格式或者不能为空");
}
//号码正确,再往手机发送验证码
try {
userService.sendCode(phone);
return new Result(true, "发送成功!");
} catch (Exception e) {
e.printStackTrace();
return new Result(false, "发送失败!");
}
}
/**
* 添加用户
* @param user 用户对象
* @param smscode 验证码
* @return
*/
@RequestMapping("/add")
public Result add(@RequestBody User user, String smscode){
try {
//短信发送完成,进行手机号,和验证码的验证,提交
boolean isCheck = userService.checkSmsCode(user.getPhone(), smscode);
//验证通过,就封装,注册账号的对象
if (!isCheck) {
return new Result(false, "手机号或者验证码不正确!");
}
user.setStatus("Y");
user.setCreated(new Date());
user.setUpdated(new Date());
user.setSourceType("1");
userService.add(user);
return new Result(true, "用户注册成功!");
} catch (Exception e) {
e.printStackTrace();
return new Result(false, "用户注册失败!");
}
}
}
2.写用户验证的接口和实现类
public interface UserService {
public Result sendCode(String phone);
public boolean checkSmsCode(String phone,String smscode);
public void add(User user);
}
——————用户实现类————————————
public class UserServiceImpl implements UserService {
//队列对象的名字,ioc容器中
@Autowired
private ActiveMQQueue smsDestination;
//消息中间键模板对象
@Autowired
private JmsTemplate jmsTemplate;
@Autowired
private RedisTemplate redisTemplate;
//发送消息,需要的阿里云通信的,模板签名和项目名称,通过配置文件赋值
@Value("${template_code}")
private String template_code;
//项目名称
@Value("${sign_name}")
private String sign_name;
@Autowired
private UserDao userDao;
@Override
public Result sendCode(String phone) {
//1. 生成一个随机6为数字, 作为验证码
StringBuffer sb = new StringBuffer();
for (int i = 1; i < 7 ; i++) {
int s = new Random().nextInt(10);
sb.append(s);
}
//把拼接好的6个随机数,转为final,String
final String smsCode = sb.toString();
//2. 手机号作为key, 验证码作为value保存到redis中, 生存时间为10分钟
redisTemplate.boundValueOps(phone).set(smsCode,60*10, TimeUnit.SECONDS);
//3. 将手机号, 短信内容, 模板编号, 签名封装成map消息发送给消息服务器
//往消息中间键对象,中的smsDestination点对点队列,发送消息对象
jmsTemplate.send(smsDestination, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
//发送消息中的具体内容是
MapMessage message = session.createMapMessage();
message.setString("mobile", phone);//手机号
message.setString("template_code", template_code);//模板编码
message.setString("sign_name", sign_name);//签名
Map map=new HashMap();
map.put("code", smsCode); //验证码
message.setString("param", JSON.toJSONString(map));
return (Message) message;
}
});
return null;
}
//验证方法
@Override
public boolean checkSmsCode(String phone, String smsCode) {
if (phone == null || smsCode == null || "".equals(phone) || "".equals(smsCode)) {
return false;
}
//1. 根据手机号到redis中获取我们自己存的验证码
String redisSmsCode = (String) redisTemplate.boundValueOps(phone).get();
//2. 判断页面传入的验证码和我们自己存的验证码是否一致
if (smsCode.equals(redisSmsCode)){
//一样,可以注册
return true;
}
return false;
}
//保存账户的方法
@Override
public void add(User user) {
userDao.insertSelective(user);
}
}
注意实现类中的jms消息中间件模板对象的ben配置要写
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:jms="http://www.springframework.org/schema/jms"
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">
<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供-->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.200.128:61616"/>
</bean>
<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
<property name="targetConnectionFactory" ref="targetConnectionFactory"/>
</bean>
<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
<!--这个是队列目的地,点对点的 文本信息-->
<bean id="smsDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="sms"/>
</bean>
</beans>