1. 项目需求 135
1.1 注册学生
phone必须唯一,如果已将存在了手机号,注册失败
int addstudent(Student student);
返回值int
1:注册成功
2:手机号已存在
name至少两个字符,age必须大于0
1.2 查询学生
根据id查询,此学生
先到redis查询学生,如果redis没有此学生,从数据库查,把查询到的学生放到redis。后面再次查询这个学生应该从redis就能获取到
Student queryStudent(Integer id);
1.3 使用Dubbo框架
addStudent,queryStudent是服务者提供实现的,消费者可以是一个Controller,调用提供者的两个方法,实现注册和查询
1.4 页面使用html和ajax,jquery
在html页面中提供form注册学生,提供文本输入id,进行查询,注册和查询都使用ajax技术
html,query.js都放入到resources/static目录中
2. 公共资源的内容资源接口 135
创建一个普通maven项目course19
实体类student
package com.bjpowernode.model;
import java.io.Serializable;
//实体类 135
public class Student implements Serializable {
//序列化后添加脚本号
private static final long serialVersionUID = 1901229007746699151L;
private Integer id;
private String name;
private String phone;
private Integer age;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", phone='" + phone + '\'' +
", age=" + age +
'}';
}
public Student() {
}
public Student(Integer id, String name, String phone, Integer age) {
this.id = id;
this.name = name;
this.phone = phone;
this.age = age;
}
public static Student defaultStudent(){
Student student = new Student();
student.setId(0);
student.setName("-");
student.setPhone("-");
return student;
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
资源接口StudentService
package com.bjpowernode.service;
import com.bjpowernode.model.Student;
//定义Dubbo接口资源 135
public interface StudentService {
//添加
int addStudent(Student student);
//查询
Student queryStudent(Integer id);
}
3. 提供者 135
创建一个springboot项目,接入mysql驱动,mybatis框架,redis
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.7.12</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bjpowernode</groupId>
<artifactId>course19_1</artifactId>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--dubbo依赖 135-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!--zookeeper依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>2.7.8</version>
<type>pom</type>
<!--排除重复的log4j依赖-->
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!--jackson依赖 136-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.11.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.11.4</version>
</dependency>
<!--公共资源接口依赖-->
<dependency>
<groupId>com.bjpowewrnode</groupId>
<artifactId>course19</artifactId>
<version>1.0.0</version>
</dependency>
<!--redis起步依赖 135-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<!--mybatis驱动-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</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>
资源接口实现类StudentServiceImpl
package com.bjpowernode.demo.service.impl;
import com.bjpowernode.model.Student;
import com.bjpowernode.service.StudentService;
//提供者 公共资源接口实现类 135
public class StudentServiceImpl implements StudentService {
//添加方法
//1 添加成功
//2 手机号已存在
@Override
public int addStudent(Student student) {
return 0;
}
@Override
public Student queryStudent(Integer id) {
return null;
}
}
application.properties
# 配置dubbo 135
spring.application.name=studentservice-provider
dubbo.scan.base-packages=com.bjpowernode.demo.service
dubbo.registry.address=zookeeper://localhost:2181
#配置redis
spring.redis.host=localhost
spring.redis.port=6379
#密码
#spring.redis.password=123
#配置mybatis
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#数据源 datasource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springdb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=lzl
dao 接口
package com.bjpowernode.demo.dao;
import com.bjpowernode.model.Student;
import org.apache.ibatis.annotations.Param;
//持久层 实现类框架会帮助我们实现 135
public interface StudentDao {
//按手机号查询
Student selectByPhone(@Param("phone")String phone);
//添加数据
int insertStudent(Student student);
}
在resources目录下的mapper目录
mybatis的sql映射文件StudentDao.xml
<?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.bjpowernode.demo.dao.StudentDao">
<!-- mybatis的sql映射文件 -->
<!--按手机号查询 135 -->
<select id="selectByPhone" resultType="com.bjpowernode.model.Student">
select * from student2 where phone=#{phone}
</select>
<!--添加数据 135-->
<insert id="insertStudent">
insert into student2(name,phone,age) values(#{name},#{phone},#{age})
</insert>
</mapper>
公共资源接口实现类StudentServiceImpl
package com.bjpowernode.demo.service.impl;
import com.bjpowernode.demo.dao.StudentDao;
import com.bjpowernode.model.Student;
import com.bjpowernode.service.StudentService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import javax.annotation.Resource;
//提供者 公共资源接口实现类 135
//暴露dubbo的服务
@DubboService(interfaceClass = StudentService.class,version = "1.0",timeout = 5000)
public class StudentServiceImpl implements StudentService {
@Resource
private StudentDao studentDao;
//声明redis模板对象 136
@Resource
private RedisTemplate redisTemplate;
//添加方法 135
//1 添加成功
//2 手机号已存在
//3 没有手机号
@Override
public int addStudent(Student student) {
int result = 0;
//查询手机号是否唯一
if(student.getPhone()!=null){
Student stu = studentDao.selectByPhone(student.getPhone());
if(stu!=null){//手机号已存在
result=2;
}else {//手机号不存在。进行添加处理
//添加处理
result=studentDao.insertStudent(student);
}
}else {
result=3;
}
return result;
}
//查询功能 136
@Override
public Student queryStudent(Integer id) {
//从redis查询Student使用json存储对对象
//设置key的序列化方式为String
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式为json
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Student.class));
final String USER_KEY="STUDENT:";
Student student=null;
//首先在redis中查询 id
if(id!=null){
//id样子 STUDENT:1001
String key = USER_KEY + id;
student = (Student) redisTemplate.opsForValue().get(USER_KEY + id);
System.out.println(id+"从redis中查询数据"+student);
if (student==null) {//redis中没查到,student为空,就在redis中添加这个数据
//从数据库中查
student = studentDao.selectById(id);
System.out.println(id+"从数据库中查询数据"+student);
if(student!=null){//数据库中查出来不为空
//存入redis
redisTemplate.opsForValue().set(key,student);
}else {
//数据库也没有
//如果redis和数据库中都没有的话,就会出现缓存穿透问题
//解决缓存穿透问题,将Student中定义的默认数据存入redis
redisTemplate.opsForValue().set(key,Student.defaultStudent());
}
}
}
return student;
}
}
提供者的主启动类
Course191Application
package com.bjpowernode;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo //启动dubbo
@MapperScan(basePackages = "com.bjpowernode.demo.dao")//为了实现dao接口
public class Course191Application {
public static void main(String[] args) {
SpringApplication.run(Course191Application.class, args);
}
}
4. 消费者 136
创建一个springboot项目 天界web依赖
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.7.12</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bjpowernode</groupId>
<artifactId>course19_2</artifactId>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--dubbo依赖 136-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!--zookeeper依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>2.7.8</version>
<type>pom</type>
<!--排除重复的log4j依赖-->
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!--公共资源接口依赖-->
<dependency>
<groupId>com.bjpowewrnode</groupId>
<artifactId>course19</artifactId>
<version>1.0.0</version>
</dependency>
<!--web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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>
application.properties
#指定端口号
server.port=9001
server.servlet.context-path=/demo
#dubbo
spring.application.name=demo-consumer
dubbo.registry.address=zookeeper://localhost:2181
dubbo.scan.base-packages=com.bjpowernode.democonsumer
控制类DubboController
package com.bjpowernode.democonsumer.controller;
import com.bjpowernode.model.Student;
import com.bjpowernode.service.StudentService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
//消费者 136
@RestController
public class DubboController {
@DubboReference(interfaceClass = StudentService.class,version = "1.0")
private StudentService studentService;
@PostMapping("/student/add")
public String addStudent(Student student){
//对student的数据做处理,name需要有值,phone,age必须有值
int result = studentService.addStudent(student);
String msg = "请稍后处理";
if(result==1){
msg = "添加学生:"+student.getName()+",成功";
}else if(result==2){
msg=student.getPhone()+",此手机号已经注册过,请更换手机号";
}else{
msg="手机号为空";
}
return "消费者添加学生的结果:"+msg;
}
}
消费者主启动类Course192Application
package com.bjpowernode;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo
public class Course192Application {
public static void main(String[] args) {
SpringApplication.run(Course192Application.class, args);
}
}
初步测试添加功能
继续完成查询功能
控制类DubboController
package com.bjpowernode.democonsumer.controller;
import com.bjpowernode.model.Student;
import com.bjpowernode.service.StudentService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
//消费者 136
@RestController
public class DubboController {
@DubboReference(interfaceClass = StudentService.class,version = "1.0")
private StudentService studentService;
//增加学生
@PostMapping("/student/add")
public String addStudent(Student student){
//对student的数据做处理,name需要有值,phone,age必须有值
int result = studentService.addStudent(student);
String msg = "请稍后处理";
if(result==1){
msg = "添加学生:"+student.getName()+",成功";
}else if(result==2){
msg=student.getPhone()+",此手机号已经注册过,请更换手机号";
}else{
msg="手机号为空";
}
return "消费者添加学生的结果:"+msg;
}
//查询学生 136
@GetMapping("/student/query")
public String queryStudent(Integer id){
String msg = "";
Student student=null;
if(id !=null && id>0){
student = studentService.queryStudent(id);
if(student!=null){
msg = "查询的学生信息:"+student.toString();
}else{
msg="没有查询到";
}
}else {
msg = "查询的id不正确";
}
return msg;
}
}
5. 写查询页面 134
static目录下的html目录下query.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>查询学生 134</title>
<!--引入js库 134-->
<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
</head>
<input type="text" id="stuId" value=""/><br>
<button id="btn">查询</button><br>
</body>
<script type="text/javascript">
$(function (){
$("#btn").click(function (){
var stuId = $("#stuId").val();
$.ajax({
url:"/demo/student/query",
type:"get",
//data:"id="+stuId,
data:{id:stuId},
dataType:"text",
success:function (data){
alert(data);
}
})
})
})
</script>
</html>