RabbitMQ实践应用一

Hello, 大家好,我是一名在互联网捡破烂的程序员

经过我们单打独斗的能力,我们终于将RabbitMQ的基本知识掌握完成了。

当你看到这篇文章的时候,如果你还是一个只有0级的勇士,那么你就靠着你坚定的信念去学习这些基础知识

打怪升级我们要一步一个脚印,过了一关有一关,这样我们才能体会到成就感

RabbitMQ基本使用一(简单介绍)

RabbitMQ基本使用二(简单队列)

RabbitMQ基本使用三(工作队列)

RabbitMQ基本使用四(发布/订阅模式)

RabbitMQ基本使用五(路由模式)

RabbitMQ基本使用六(主题模式)

你说是不是呢?

在此之前呢,这些呢都是我自己理解的一些比较片面的知识点,如有问题,请多多包含,我其实也是一个小菜鸟,但是呢,我觉得虽然可能我的文章写得比较差,但是这并不会阻止我学习的进步。我也希望通过自己的学习来和大家分享自己的知识点。

我相信大家都是从小白慢慢成长为他们眼中的大神,但是我对那些并不是羡慕,我对他们知识仰慕,敬佩。

为什么别人就可以学的那么好,就可以写出好的文章,我应该向他们学习哪些优点。

俗话说:三人行必有我师焉

如果我们每天学习一点一点,每天进步一点一点,虽然在短暂的时间我们可能不会看到自己有什么很大的成果,但是我们每天都会收获一点知识,那么我们可以成长起来。

说实话,本人的大学也不是很好,也就是一个普通的二本学校,但是我并没有因为自己的学校比别人的学校差,就觉得自己比别人矮一等。

OK,说了这么多,要相信自己,美好的一天会到来的。

越努力,越幸运

加油吧,少年~

如果你现在已经将前面的关都完成的比较好,那么我觉得你可以进入我们的下一个区域,那就是实战演地。

那就开始我们的操作吧

今天是给大家带来的是消息的异步操作。

所谓异步操作呢,就是我们其实是在执行两个事情,但是呢我们并不是同时执行,我们错开执行的。你不影响我,我不影响你

一、简单概述

不管在什么地方,我们可能都会遇到登录的操作吧,那么你知道登录的背后究竟干了什么?我们的登录状态?

登录日志?这些呢,可能还不了解。不过这些都是我瞎编的,哈哈哈哈

好吧。算了,下面开始了,不再绕弯子了

二、场景介绍

我们也是在登录过程中,通常会把登录的日志保存起来,那么在执行登录和保存这是两个线程,我们怎么保证程序稳定呢?

假设我们在登录时,就直接执行我们的登录日志保存操作,这样做是可以的,但是呢,这样我们就是一个线程在进行,如果我们登录验证成功了,但是我们的日志保存失败了,那么返回给我我们用户的就是500,这样是很不友好的。

用户说:我明明账号密码都是正确的啊,为什么给我什么看不懂的页面。

这样给用户的体验是很不好的,这什么垃圾系统。溜了溜了

其实在我们系统中登录操作和日志保存操作是异步的,我们不管登录没登录成功,这样我们都是要保存我们的日志信息。

那么我们应该怎么解决呢?

三、解决方案

通过上诉的问题,我们第一时间想到的是什么呢?

其实我们可以使用Spring中的AOP来帮助我们解决,我们只需要定义切点,切入到我们要监听的方法就可以啦。

但是,既然我们选择了这一条路。我们就要运用到实践中。那他是谁呢?

没错,就是我们的主角RabbitMQ

还是没有给出解决方法呢?

登录操作的时候我们登录验证成功了,那我们可以向队列中发送消息,告诉有用户登录进来来,需要我们保存好登录日志,这样我们就可以和登录错开啦,你不妨碍我,我也不会坑你。

那么我们的具体代码是什么呢?

开始我们的表演

四、实战开始

在开始之前呢,如有问题,请多多包含

首先呢,先要创建一个SpringBoot项目,这就不用过多的介绍吧。现在基本上都是使用SpringBoot来开发我们的项目

1. 基本配置

1.1 先来我们的POM文件
<dependencies>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>


<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.5.9.RELEASE</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>

<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

这么没有什么特别的,主要是要引入我们的amqp

1.2 修改我们的application.yml文件
server:
port: 9000

#应用名称
spring:
#Thymeleaf取消缓存
thymeleaf:
cache: false
#jpa的配置
jpa:
show-sql: true
database-platform: org.hibernate.dialect.MySQL5Dialect
#数据库配置
datasource:
url: jdbc:mysql://localhost:3306/test_rabbitmq?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: wrf123
#消息队列配置
rabbitmq:
host: localhost
virtual-host: /
username: guest
password: guest
template:
exchange: USER.EXCHANGE

配置我们的基本参数,主要是对数据库和RabbitMQ的配置

这里我们是使用JPA作为数据持久层

没有学习过JPA的小伙伴,可以直接学习一下哦

1.3 数据库文件
/*
Navicat Premium Data Transfer

Source Server : dreamcode
Source Server Type : MySQL
Source Server Version : 50729
Source Host : localhost:3306
Source Schema : test_rabbitmq

Target Server Type : MySQL
Target Server Version : 50729
File Encoding : 65001

Date: 14/04/2020 20:49:49
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for test_log
-- ----------------------------
DROP TABLE IF EXISTS `test_log`;
CREATE TABLE `test_log` (
`log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志Id',
`log_user_name` varchar(255) DEFAULT NULL COMMENT '登录用户名',
`log_user_email` varchar(255) DEFAULT NULL COMMENT '登录邮箱',
PRIMARY KEY (`log_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of test_log
-- ----------------------------
BEGIN;
INSERT INTO `test_log` VALUES (1, 'FC', '123@qq.com');
COMMIT;

-- ----------------------------
-- Table structure for test_user
-- ----------------------------
DROP TABLE IF EXISTS `test_user`;
CREATE TABLE `test_user` (
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`user_name` varchar(255) NOT NULL COMMENT '用户名称',
`user_password` varchar(255) DEFAULT NULL COMMENT '用户密码',
`user_email` varchar(255) DEFAULT NULL COMMENT '用户邮箱',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of test_user
-- ----------------------------
BEGIN;
INSERT INTO `test_user` VALUES (10000, 'FC', '123456', '123@qq.com');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

2. 创建我们的公共类

ApiResponse

package com.codeworld.rabbitmqdemo.rabbitmq.common;

import java.util.HashMap;

/**
* 数据响应格式
* @author dreamcode
*/
public class ApiResponse extends HashMap<String, Object> {

/**
* 状态
*/
private Integer code;

/**
* 信息
*/
private String msg;

@Override
public Object put(String key, Object value) {

super.put(key,value);

return this;
}

/**
* 状态
* @param code
* @return
*/
public ApiResponse code(Integer code){

this.put("code", code);

return this;
}

/**
* 信息
* @param msg
* @return
*/
public ApiResponse msg(String msg){

this.put("msg", msg);

return this;
}
}

User

package com.codeworld.rabbitmqdemo.rabbitmq.entity;

import lombok.Data;

import javax.persistence.*;

/**
* 用户基本类
* @author dreamcode
*/
@Table(name = "test_user")
@Entity
@Data
public class User {

/**
* 用户Id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;

/**
* 用户姓名
*/
private String userName;

/**
* 用户密码
*/
private String userPassword;

/**
* 用户邮箱
*/
private String userEmail;
}

Log

package com.codeworld.rabbitmqdemo.rabbitmq.entity;

import lombok.Data;
import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

/**
* 日志类
* @author dreamcode
*/
@Table(name = "test_log")
@Entity
@Data
public class Log {


/**
* 日志Id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long logId;

/**
* 登录用户名
*/
private String logUserName;

/**
* 登录邮箱
*/
private String logUserEmail;
}

3. User相关代码

这个是用来作为我们的数据持久层,通常我们使用最多的是MyBatis吧。

这里我们就要换一种风格,毕竟技多不压身

3.1 创建UserRepository

UserRepository

package com.codeworld.rabbitmqdemo.rabbitmq.repository;

import com.codeworld.rabbitmqdemo.rabbitmq.entity.User;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import java.util.Optional;
/**
* 用户Repository
* @author dreamcode
*/
@Repository
public interface UserRepository extends JpaRepository<User, Long> , JpaSpecificationExecutor<User> {}

我们继承了Jpa的两个基本类,这样使用的好处是,除去了我们复杂的配置文件,直接使用它里面封装好的方法

这样可以极大的简化我们的开发效率

3.2 UserService方法

UserService

package com.codeworld.rabbitmqdemo.rabbitmq.service;

import com.codeworld.rabbitmqdemo.rabbitmq.common.ApiResponse;

/**
* @author dreamcode
*/
public interface UserService {

/**
* 登录
* @param userName
* @param password
* @return
*/
ApiResponse login(String userName, String password);
}
3.3 UserServiceImpl方法

UserServiceImpl

package com.codeworld.rabbitmqdemo.rabbitmq.service.impl;

import com.codeworld.rabbitmqdemo.rabbitmq.common.ApiResponse;
import com.codeworld.rabbitmqdemo.rabbitmq.entity.User;
import com.codeworld.rabbitmqdemo.rabbitmq.repository.UserRepository;
import com.codeworld.rabbitmqdemo.rabbitmq.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
* 用户Service
*
* @author dreamcode
*/
@Service
public class UserServiceImpl implements UserService {

private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

@Autowired(required = false)
private UserRepository userRepository;

@Autowired(required = false)
private AmqpTemplate amqpTemplate;

/**
* 登录
*
* @param userName
* @param password
* @return
*/
@Override
public ApiResponse login(String userName, String password) {

// 判断参数
if (StringUtils.isBlank(userName)) {

return new ApiResponse().code(400).msg("请输入用户名");
}

if (StringUtils.isBlank(password)) {

return new ApiResponse().code(400).msg("请输入密码");
}

Specification<User> specification = new Specification<User>() {

List<Predicate> list = new ArrayList<>();


@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

list.add(criteriaBuilder.equal(root.get("userName").as(String.class), userName));

Predicate[] predicates = new Predicate[list.size()];

return criteriaBuilder.and(list.toArray(predicates));
}
};

try {

Optional<User> optionalUser = this.userRepository.findOne(specification);

if (!optionalUser.isPresent()){

return new ApiResponse().code(400).msg("用户名或密码错误");
}

User user = optionalUser.get();

// 判断密码
if (!StringUtils.equals(user.getUserPassword(), password)) {

return new ApiResponse().code(400).msg("用户名或密码错误");
}

// 异步添加用户登录日志
this.amqpTemplate.convertAndSend("user.log.add", user.getUserId());

// 登录成功
return new ApiResponse().code(200).msg("登录成功");

} catch (Exception e) {

LOGGER.error("登录出现异常");

return new ApiResponse().code(500).msg("服务器异常");
}
}
}

注意代码中的注释

当我们登录验证成功后,我们就换将消息发送出去

// 异步添加用户登录日志
this.amqpTemplate.convertAndSend("user.log.add", user.getUserId());

方法中的第一个参数是我们定义的路由名称,第二个参数是我们传过去的用户Id

相当于是我们要发送的消息

其实就是我们生产者发送的消息

这样就可以保证就算我们程序出错了,但是不会影响我们登录

3.4 UserController
package com.codeworld.rabbitmqdemo.rabbitmq.controller;

import com.codeworld.rabbitmqdemo.rabbitmq.common.ApiResponse;
import com.codeworld.rabbitmqdemo.rabbitmq.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
* 用户Controller
* @author dreamcode
*/
@Controller
@RequestMapping("user")
public class UserController {

@Autowired(required = false)
private UserService userService;

/**
* 登录
* @return
*/
@PostMapping("login")
public ResponseEntity<ApiResponse> login(@RequestParam("userName") String userName,
@RequestParam("password") String password){
ApiResponse apiResponse = this.userService.login(userName, password);

return ResponseEntity.ok(apiResponse);
}
}

这些代码就不用多说吧

OK,User的相关代码就到此结束了,那么不知道你有没有懂呢?

没懂没关系,我们可以在看一遍呀~

不过我们既然发送了消息,怎么没看见消费者呢?

不要慌,他来了。。。

4. 消费者(这里我们用listener来表示)

UserListener

package com.codeworld.rabbitmqdemo.rabbitmq.listener;

import com.codeworld.rabbitmqdemo.rabbitmq.entity.Log;
import com.codeworld.rabbitmqdemo.rabbitmq.entity.User;
import com.codeworld.rabbitmqdemo.rabbitmq.repository.UserRepository;
import com.codeworld.rabbitmqdemo.rabbitmq.service.LogService;
import com.codeworld.rabbitmqdemo.rabbitmq.service.UserService;
import com.codeworld.rabbitmqdemo.rabbitmq.utils.IDGeneratorUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Optional;

/**
* RabbitMQ监听
* @author dreamcode
*/
@Component
public class UserListener {


private static final Logger LOGGER = LoggerFactory.getLogger(UserListener.class);

@Autowired(required = false)
private UserRepository userRepository;

@Autowired(required = false)
private LogService logService;


/**
* 添加登录日志
*/
@RabbitListener(bindings = @QueueBinding(

value = @Queue(value = "USER.LOG", durable = "true"),

exchange = @Exchange(value = "USER.EXCHANGE", ignoreDeclarationExceptions = "true", type = ExchangeTypes.TOPIC),

key = {"user.log.add"}
))
public void save(Long userId){

try {

// 根据Id查询用户
Optional<User> optionalUser = this.userRepository.findById(userId);

if (!optionalUser.isPresent()){

LOGGER.info("没有该用户");

return;
}

// 获取用户
User user = optionalUser.get();

// 创建日志对象
Log log = new Log();

log.setLogUserName(user.getUserName());

log.setLogUserEmail(user.getUserEmail());

// 保存日志
this.logService.save(log);

LOGGER.info("消息已消费");

}catch (Exception e){

LOGGER.error("消息消费失败");
}
}
}

到这里就是我们的关键代码,我们的消费者在这里就开始消费了

4.1 首先来看我我们的这个注解

@RabbitListener

4.2我们再进一步看我们圈出来的注解

@QueueBinding

这里就不贴图了,直接上代码

@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface QueueBinding {
Queue value();

Exchange exchange();

String[] key() default {};

String ignoreDeclarationExceptions() default "false";

Argument[] arguments() default {};
}

在这里我们可以清楚的看到里面的名称,也就是我们需要使用到的~

下面来一一解释

4.3@Queue—->队列名称的声明

我们还是先来看一看源码吧

@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface Queue {
@AliasFor("name")
String value() default "";

@AliasFor("value")
String name() default "";

String durable() default "";

String exclusive() default "";

String autoDelete() default "";

String ignoreDeclarationExceptions() default "false";

Argument[] arguments() default {};
}
4.3.1 主要参数解释

value():定义队列的名称

name():应该还是定义队列的名称吧,不知道有什么区别

durable():队列是否支持持久化,就是支不支持我们队列不消失

exclusive():默认情况下,如果提供了队列名称,则它不是独占的

autoDelete():当这个队列没有使用时,是否自动删除。默认情况下,是不会自动删除的。若要设置自动删除,则设置为true

4.3.2 我们自己定义的
@Queue(value = "USER.LOG", durable = "true")

我们这里只定义了队列的名称和是否持久化,需要的可以自行添加

4.3.3 看看界面上是否有该队列

4.4@Exchange—->交换机名称的声明

源码:

@Target({})
@Retention(RetentionPolicy.RUNTIME)
public @interface Exchange {

/**
* @return the exchange name.
*/
@AliasFor("name")
String value() default "";

/**
* @return the exchange name.
* @since 2.0
*/
@AliasFor("value")
String name() default "";

/**
* The exchange type, including custom.
* Defaults to {@link ExchangeTypes#DIRECT}.
* If a custom exchange type is used the corresponding plugin is required on the broker.
* @return the exchange type.
* @see ExchangeTypes
*/
String type() default ExchangeTypes.DIRECT;

/**
* @return false if the exchange is to be declared as non-durable.
*/
String durable() default "true";

/**
* @return true if the exchange is to be declared as auto-delete.
*/
String autoDelete() default "false";

/**
* @return true if the exchange is to be declared as internal.
* @since 1.6
*/
String internal() default "false";

/**
* @return true if the declaration exceptions should be ignored.
* @since 1.6
*/
String ignoreDeclarationExceptions() default "false";

/**
* @return true if the exchange is to be declared as an
* 'x-delayed-message' exchange. Requires the delayed message exchange
* plugin on the broker.
* @since 1.6.4
*/
String delayed() default "false";

/**
* @return the arguments to apply when declaring this exchange.
* @since 1.6
*/
Argument[] arguments() default {};

}
4.4.1 主要参数解释

value():交换机名称

name():应该也是用来定义交换机名称

type():交换机的类型:默认是direct(路由模式),其他还有topicfanoutheaderssystem

durable():是否支持持久化:默认情况下是true

autoDelete():是否支持自动删除:默认情况下是不支持自动删除,若要自动删除:将其设置为true

4.4.2 我们自己定义的
exchange = @Exchange(value = "USER.EXCHANGE", ignoreDeclarationExceptions = "true", type = ExchangeTypes.TOPIC
4.4.3 看看界面上是否有该交换机

4.5@Key—-> 路由键的名称

我们可以看到这个是一个数组类型,我们可以定义多个路由键

4.5.1 我们自己定义的
key = {"user.log.add"}

我们这里定义的和生产者定义的一致

// 异步添加用户登录日志
this.amqpTemplate.convertAndSend("user.log.add", user.getUserId());
4.5.2 看看我们交换机是否绑定该路由

OK,我们主要的基本参数就解释到这里啦,具体的需要自己去查阅文档哦

那么到这里我们消费者的工作就做完了

其实也没有什么难点,主要在与那些注解的运用,知道每个注解的意思就可以了。

那么接下来就是日志保存的代码啦

5、Log相关代码

LogRepository

package com.codeworld.rabbitmqdemo.rabbitmq.repository;

import com.codeworld.rabbitmqdemo.rabbitmq.entity.Log;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;

/**
* 日志Repository
* @author dreamcode
*/
@Repository
public interface LogRepository extends JpaRepository<Log, Long>, JpaSpecificationExecutor<Log> {}

LogService

package com.codeworld.rabbitmqdemo.rabbitmq.service;

import com.codeworld.rabbitmqdemo.rabbitmq.entity.Log;

/**
* @author dreamcode
*/
public interface LogService {

/**
* 保存日志
* @param log
*/
void save(Log log);
}

LogServiceImpl

package com.codeworld.rabbitmqdemo.rabbitmq.service.impl;

import com.codeworld.rabbitmqdemo.rabbitmq.entity.Log;
import com.codeworld.rabbitmqdemo.rabbitmq.repository.LogRepository;
import com.codeworld.rabbitmqdemo.rabbitmq.service.LogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
* 日志Service
* @author dreamcode
*/
@Service
public class LogServiceImpl implements LogService {

private static final Logger LOGGER = LoggerFactory.getLogger(LogServiceImpl.class);

@Autowired(required = false)
private LogRepository logRepository;

/**
* 保存日志
* @param log
*/
@Override
public void save(Log log) {

try {

this.logRepository.save(log);

LOGGER.info("日志保存成功");

}catch (Exception e){

LOGGER.error("日志保存失败");
}
}
}

这些就不用过多的解释吧,都是些基本操作

OK,到这里我们的代码就后端代码就全部完成啦

接下来就是我们检验成果的时候了

五、成果演示

1. 首先还要创建我们的页面

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
<body>

<form action="#">

用户名:<input type="text" class="userName">
<br>
密 码:<input type="password" class="password">
<br>
<input type="submit" value="登录" class="login">

</form>

</body>

<script>

/**
* 登录
*/
$(".login").click(function () {

// 获取参数
var userName = $(".userName").val();

var password = $(".password").val();

if (userName == ''){

alert("用户名不能为空");

return;
}

if (password == ''){

alert("密码不能为空");

return;
}

// 实现登录
$.post('/user/login',{userName: userName, password: password},function (data) {

if (data.code == '400'){

alert(data.msg);

return;
}

if (data.code == '500'){

alert(data.msg);

return;
}

if (data.code == '200'){

window.location.href='/page/index.html';
}

})
});

</script>
</html>

这种我们都是练熟了的,不用手把手教吧

哈哈哈

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
登录成功
</body>
</html>

2. 创建我们页面Controller

ViewController

package com.codeworld.rabbitmqdemo.rabbitmq.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* 页面控制Controller
* @author dreamcode
*/
@Controller
@RequestMapping("page")
public class ViewController {


/**
* 登录页面
* @return
*/
@RequestMapping("login.html")
public String login(){

return "login";
}

/**
* 首页
* @return
*/
@RequestMapping("index.html")
public String index(){

return "index";
}
}

3. 截图演示

3.1 先看数据库信息
  • user

  • log

3.2 登录页面

3.3 看我们控制台打印的信息

如果执行登录操作,就会异步执行我们的日志保存操作
3.4 看我们的数据库信息

3.5 跳转到我们的首页

OK,到这里我们的任务就全部完成呐。。。

说实话,是有点累哈。。。

不过苦中有甜。

六、结束

OK,在这里我们的实践操作一就到这里了,不知道你有没有帮助到你呢?

看到这里的人都是技术人才,你的浏览就是我前进的动力

欢迎加入QQ群: