使用Springboot开发系统配置工作简洁,提供丰富的注解,开发工程师可以快速完成项目的开发工作,不仅提高项目开发效率,系统维护工作也更加简化,本例使用SpringBoot完成多对多的案例,本例要求表单数据必须保持到消息服务器RabbitMQ中,设计定时器从队列中获取消息并解析到数据库,所有与数据库操作的业务模块要求使用Dubbo服务完成,也就是Web端系统只包含Spring Controller层业务逻辑,Mapper层和Service层都由Dubbo托管,这样设计是为了提供项目高可用和负载均衡,Dubbo服务可以利用Dubbo框架提供集群服务。
本例要求:
- 安装Dubbo注册中心ZooKeeper
- 安装RabbitMQ服务
- 可选部署Dubbo控制台程序
架构图
Dubbo服务端程序
新建Maven POM文件
<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>GuFang</groupId>
<artifactId>HrServer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>HrServer</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>1.0.1</version>
</dependency>
<!--
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.1-SNAPSHOT</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>1.3.0</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.11</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>jconsole</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>tools</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
</project>
Application.yml配置文件
server:
port: 9090
context-path: /
spring:
#Dubbo 1.0.1集成
dubbo:
appname: dubbo-service
registry: zookeeper://192.168.137.1:2181
protocol: dubbo
port: 20880
#Dubbo 2.1.0集成
# dubbo:
# application:
# name: dubbo-service
# registry:
# address: zookeeper://192.168.137.1:2181
# protocol:
# name: dubbo
# port: 20880
#数据源配置
datasource:
name: w1
url: jdbc:mysql://127.0.0.1:3306/w1?useUnicode=true&characterEncoding=utf8
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
#Mybatis实体类配置
mybatis:
mapper-locations: classpath:mapper/*.xml
新建实体类
MenuInfo.java 菜单表实体类
package com.test.bean;
import java.io.Serializable;
//菜单表实体类
public class MenuInfo implements Serializable{
private Integer id = null;
private String name = null;
private Integer price = null;
//冗余字段,存放材料名称,以逗号分隔
private String sname = null;
//冗余字段,存放材料ID,以逗号分隔
private String sid = null;
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 Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
}
StaffInfo.java 材料表实体类
package com.test.bean;
import java.io.Serializable;
//材料表实体类
public class StaffInfo implements Serializable{
private Integer id = null;
private String name = null;
//冗余字段,代表前台页面Checkbox控件是否选中,true为选中
private String checked = "";
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 getChecked() {
return checked;
}
public void setChecked(String checked) {
this.checked = checked;
}
}
M2SInfo.java 中间关联表(关联菜单与材料表,实现多对多业务)
package com.test.bean;
import java.io.Serializable;
//菜单关联材料的实体类
public class M2SInfo implements Serializable{
//菜单表ID
private Integer mid = null;
//材料表ID
private Integer sid = null;
public Integer getMid() {
return mid;
}
public void setMid(Integer mid) {
this.mid = mid;
}
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
}
新建Mybatis Mapper.xml
Mapper.xml文件需要位于src/main/resources/mapper目录下
<?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.test.mapper.MenuMapper">
<select id="findMenu" resultType="com.test.bean.MenuInfo">
select * from t_menu where name like '%${name}%'
</select>
<select id="findStaff" resultType="com.test.bean.StaffInfo">
select * from t_staff
</select>
<insert id="saveMenu" parameterType="com.test.bean.MenuInfo"
useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into t_menu(name,price) values(#{name},#{price})
</insert>
<update id="updateMenu" parameterType="com.test.bean.MenuInfo">
update t_menu set name=#{name},price=#{price} where id=#{id}
</update>
<delete id="deleteMenu" parameterType="Integer">
delete from t_menu where id=#{id}
</delete>
<insert id="saveM2S" parameterType="com.test.bean.M2SInfo">
insert into t_m2s(mid,sid) values(#{mid},#{sid})
</insert>
<delete id="deleteM2S" parameterType="Integer">
delete from t_m2s where mid=#{id}
</delete>
<select id="findMenu2" resultType="com.test.bean.MenuInfo">
select a.*,b.sname,b.sid from t_menu a left join
(select group_concat(s.name) sname,group_concat(s.id) sid,m2s.mid from t_staff s,t_m2s m2s where s.id=m2s.sid group by m2s.mid) b
on a.id=b.mid where a.name like '%${name}%' or b.sname like '%${name}%'
</select>
<select id="getMenuById" resultType="com.test.bean.MenuInfo">
select a.*,b.sname,b.sid from t_menu a left join
(select group_concat(s.name) sname,group_concat(s.id) sid,m2s.mid from t_staff s,t_m2s m2s where s.id=m2s.sid group by m2s.mid) b
on a.id=b.mid where a.id=#{id}
</select>
</mapper>
数据库SQL脚本
create table t_menu(id int auto_increment primary key,
name varchar(40),
price int);
create table t_staff(id int auto_increment primary key,
name varchar(40));
create table t_m2s(mid int,sid int);
insert into t_staff(name) values('鸡肉');
insert into t_staff(name) values('花生米');
insert into t_staff(name) values('猪肉');
insert into t_staff(name) values('木耳');
insert into t_menu(name,price) value('宫保鸡丁',18);
insert into t_menu(name,price) value('土豆丝',20);
insert into t_m2s (mid,sid) values (1,1);
insert into t_m2s (mid,sid) values (1,4);
insert into t_m2s (mid,sid) values (2,2);
insert into t_m2s (mid,sid) values (2,3);
关联中间表与材料表,获取材料名称,材料ID和菜单ID
select s.name,s.id,m2s.mid from t_staff s,t_m2s m2s where s.id=m2s.sid
select group_concat(s.name) sname,group_concat(s.id) sid,m2s.mid from t_staff s,t_m2s m2s where s.id=m2s.sid group by m2s.mid
select a.*,b.sname,b.sid from t_menu a left join
(select group_concat(s.name) sname,group_concat(s.id) sid,m2s.mid from t_staff s,t_m2s m2s where s.id=m2s.sid group by m2s.mid) b
on a.id=b.mid;
新建Mybatis接口
MenuMapper.java需要创建在包com.test.mapper下
package com.test.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.test.bean.M2SInfo;
import com.test.bean.MenuInfo;
import com.test.bean.StaffInfo;
//Mybatis接口主键,Springboot自动扫描
@Mapper
public interface MenuMapper {
//根据菜单名称查询菜单结果,@Param("name")标注参数名可以使用在SQL语句中
public List<MenuInfo> findMenu(@Param("name") String name);
//返回全部材料列表
public List<StaffInfo> findStaff();
//保存菜单对象
public void saveMenu(MenuInfo mi);
//更新菜单对象
public void updateMenu(MenuInfo mi);
//根据菜单ID删除记录,@Param("id")标注参数名可以使用在SQL中
public void deleteMenu(@Param("id") Integer mid);
//保存中间表
public void saveM2S(M2SInfo m2s);
//根据菜单ID删除中间表
public void deleteM2S(@Param("id") Integer mid);
//返回多表关联查询数据
public List<MenuInfo> findMenu2(@Param("name") String name);
//根据菜单ID返回菜单对象,需要多表关联查询
public MenuInfo getMenuById(@Param("id") Integer mid);
}
新建服务类接口
MenuService.java 创建在包com.test.service下
package com.test.service;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.github.pagehelper.PageInfo;
import com.test.bean.M2SInfo;
import com.test.bean.MenuInfo;
import com.test.bean.StaffInfo;
public interface IMenuService {
//根据菜单名称查询菜单结果
public List<MenuInfo> findMenu(String name);
//返回全部材料列表
public List<StaffInfo> findStaff();
//保存菜单对象,返回保存对象,使用Dubbo远程调用需要返回对象ID
public MenuInfo saveMenu(MenuInfo mi);
//更新菜单对象
public void updateMenu(MenuInfo mi);
//根据菜单ID删除记录
public void deleteMenu(Integer mid);
//保存中间表
public void saveM2S(M2SInfo m2s);
//根据菜单ID删除中间表
public void deleteM2S(Integer mid);
//返回多表关联查询数据
public List<MenuInfo> findMenu2(String name);
//根据菜单ID返回菜单对象,需要多表关联查询
public MenuInfo getMenuById(Integer mid);
//返回分页菜单数据
public PageInfo getPageMenu(String name,Integer page,Integer rows);
}
新建服务实现类
MenuServiceImpl.java 创建在包com.test.service.impl下
package com.test.service.impl;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.test.bean.M2SInfo;
import com.test.bean.MenuInfo;
import com.test.bean.StaffInfo;
import com.test.mapper.MenuMapper;
import com.test.service.IMenuService;
//Dubbo服务注解
@com.alibaba.dubbo.config.annotation.Service(interfaceClass = IMenuService.class)
//Spring服务主键
@Service
public class MenuServiceImpl implements IMenuService{
private Logger log = LoggerFactory.getLogger(MenuServiceImpl.class);
//注入Mapper对象
@Autowired
private MenuMapper mapper;
//@Transactional代表需要开启事务控制
@Override
@Transactional(readOnly=true,propagation=Propagation.REQUIRES_NEW)
public List<MenuInfo> findMenu(String name) {
return mapper.findMenu(name);
}
@Override
@Transactional(readOnly=true,propagation=Propagation.REQUIRES_NEW)
public PageInfo getPageMenu(String name,Integer page,Integer rows) {
System.out.println("name="+name+",page="+page+",rows="+rows);
PageHelper.startPage(page, rows);
List<MenuInfo> menuList = findMenu2(name);
PageInfo pi = new PageInfo(menuList);
return pi;
}
@Override
public List<StaffInfo> findStaff() {
return mapper.findStaff();
}
@Transactional
@Override
public MenuInfo saveMenu(MenuInfo mi) {
mapper.saveMenu(mi);
return mi;
}
@Override
public void updateMenu(MenuInfo mi) {
mapper.updateMenu(mi);
}
@Override
public void deleteMenu(Integer mid) {
mapper.deleteMenu(mid);
}
@Override
public void saveM2S(M2SInfo m2s) {
mapper.saveM2S(m2s);
}
@Override
public void deleteM2S(Integer mid) {
mapper.deleteM2S(mid);
}
@Override
public List<MenuInfo> findMenu2(String name) {
return mapper.findMenu2(name);
}
@Override
public MenuInfo getMenuById(Integer mid) {
return mapper.getMenuById(mid);
}
}
创建SpringBoot启动类
Starter.java,它最好放置在根包目录,这样可以省略很多注解配置工作
package com.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
//SpringBoot核心注解,自动扫描本来所在包下的所有子包
//相当于@Configuration + @EnableAutoConfiguration + @ComponentScan
@SpringBootApplication
//开启Dubbo配置
@EnableDubboConfiguration
public class Starter {
public static void main(String[] args) {
SpringApplication.run(Starter.class, args);
}
}
启动Dubbo服务
在Zookeeper服务注册信息
SpringBoot Web端系统
新建Maven webapp项目
POM.xml文件配置
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>Test_DubboWeb</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Test_DubboWeb Maven Webapp</name>
<url>http://maven.apache.org</url>
<!-- 定义公共资源版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 添加springboot对AOP的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 添加springboot对redis的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 添加springboot对freemarker的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- 添加springboot对测试的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 添加springboot对在线开发的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
<scope>true</scope>
</dependency>
<!-- 添加springboot对amqp的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<!--
<scope>provided</scope>
-->
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!--
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.0.1-SNAPSHOT</version>
</dependency>
-->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.11</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>jconsole</artifactId>
</exclusion>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>tools</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<finalName>Test_DubboWeb</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>
Application.properties 文件配置
#SpringBoot启动端口和项目路径
server.port=6060
server.context-path=/
#spring.resources.static-locations=/css,/images,/img,/js
#SpringMVC中JSP视图配置
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
#Http编码配置
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
#Rabbitmq消息服务器配置
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
#数据源配置
spring.datasource.name=w1
spring.datasource.url=jdbc:mysql://localhost:3306/w1?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.maxActive=20
spring.datasource.initialSize=1
spring.datasource.maxWait=60000
spring.datasource.minIdle=1
#Dubbo 1.0.1集成
spring.dubbo.appname=dubbo-consumer
spring.dubbo.registry=zookeeper://192.168.137.1:2181
spring.dubbo.protocol=dubbo
spring.dubbo.port=20880
#Dubbo 2.1.0集成
#spring.dubbo.application.name=dubbo-consumer
#spring.dubbo.registry.address=zookeeper://192.168.137.1:2181
#spring.dubbo.protocol.name=dubbo
#spring.dubbo.protocol.port=20880
#日志配置
logging.file=d:/springboot.log
logging.level.com.test.mapper=INFO
logging.level.com.hk.servlet=DEBUG
logging.level.com.test.service.impl=DEBUG
新建Dubbo.properties配置文件,位于src/main/resources目录下
#Dubbo QOS Server Port
dubbo.qos.port=20221
Dubbo服务接口类可以在Web端新建,也可导入Dubbo服务的Jar包
新建Controller类
package com.test.ctrl;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.dubbo.config.annotation.Reference;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.test.bean.MenuInfo;
import com.test.bean.StaffInfo;
import com.test.service.IMenuService;
import com.test.util.PageUtil;
@Controller
public class MenuCtrl {
@Reference(check=false)
private IMenuService serv;
@Autowired
private SendMsg sendmsg;
@RequestMapping("/test")
public String test(HttpServletRequest req,Integer page,Integer rows)
{
return "add";
}
//跳转菜单列表的方法
//接收前台参数page,rows
@RequestMapping("/list")
public String list(HttpServletRequest req,Integer page,Integer rows)
{
if(page == null)
page = 1;
if(rows == null)
rows = 4;
String name = req.getParameter("name");
return toListPage(req,page,rows,name);
}
@ResponseBody
@RequestMapping("/list2")
public List<MenuInfo> list2(HttpServletRequest req,Integer page,Integer rows)
{
if(page == null)
page = 1;
if(rows == null)
rows = 4;
PageInfo pi = serv.getPageMenu("", page, rows);
List<MenuInfo> menuList2 = pi.getList();//当前页显示记录集合
return menuList2;
}
//删除方法,通过id删除菜单和中间表
@RequestMapping("/delete")
public String delete(HttpServletRequest req,Integer page,Integer rows)
{
if(page == null)
page = 1;
if(rows == null)
rows = 4;
String[] ids = req.getParameterValues("id");
if(ids != null)
{
for(String id:ids)
{
Integer mid = new Integer(id);
serv.deleteMenu(mid);
serv.deleteM2S(mid);
}
}
return toListPage(req,1,4,null);
}
//跳转到新增页面
@RequestMapping("/add")
public String add(HttpServletRequest req)
{
List<StaffInfo> staffList = serv.findStaff();
req.setAttribute("staffList", staffList);
return "add";
}
//跳转到修改页面
@RequestMapping("/modify")
public String modify(HttpServletRequest req)
{
String id = req.getParameter("id");
Integer mid = new Integer(id);
MenuInfo menu = serv.getMenuById(mid);
req.setAttribute("menu", menu);
String sid = menu.getSid();//1,2,3
System.out.println("sid="+sid);
List<StaffInfo> staffList = serv.findStaff();
for(StaffInfo si:staffList)
{
String sid2 = si.getId().toString();
if(sid.indexOf(sid2)>=0)
si.setChecked("checked");
}
req.setAttribute("staffList", staffList);
return "add";
}
//跳转到查看页面
@RequestMapping("/view")
public String view(HttpServletRequest req)
{
String id = req.getParameter("id");
Integer mid = new Integer(id);
MenuInfo menu = serv.getMenuById(mid);
req.setAttribute("menu", menu);
String sid = menu.getSid();//1,2,3
System.out.println("sid="+sid);
List<StaffInfo> staffList = serv.findStaff();
for(StaffInfo si:staffList)
{
String sid2 = si.getId().toString();
if(sid.indexOf(sid2)>=0)
si.setChecked("checked");
}
req.setAttribute("staffList", staffList);
return "view";
}
//保存菜单数据到Rabbitmq队列,返回到列表页面
@RequestMapping("/save")
public String save(HttpServletRequest req,MenuInfo mi)
{
sendmsg.send(mi);
return toListPage(req,1,4,null);
}
//公共方法,统一返回到列表页面
private String toListPage(HttpServletRequest req,Integer page,Integer rows,String name)
{
if(page == null)
page = 1;
if(rows == null)
rows = 4;
if(name == null)
name = "";
System.out.println("page===="+page+",rows==="+rows+",name="+name);
PageInfo pi = serv.getPageMenu(name, page, rows);
List<MenuInfo> menuList2 = pi.getList();//当前页显示记录集合
Long total = pi.getTotal();//数据库表全部记录数
req.setAttribute("menuList", menuList2);
System.out.println("menuList2===="+menuList2.size());
String url = "/list";
PageUtil pu = new PageUtil(url,page,rows,total);
req.setAttribute("pageDiv", pu.toHtml());
req.setAttribute("name", name);
return "menu";
}
}
新建集成Rabbitmq工具类
package com.test.ctrl;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.test.bean.MenuInfo;
import com.test.util.RabbitmqConf;
@Component
public class SendMsg {
@Autowired
private AmqpTemplate amqp;
public void send(MenuInfo mi)
{
amqp.convertAndSend(RabbitmqConf.QUEUE1,mi);
}
}
RabbitMq消息接收器可以有两种方式,可以通过定时器接收消息并处理,也可以设计监听器接受消息并处理,两种处理消息方式是互斥的
定时器消息接收器
package com.test.util;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.alibaba.dubbo.config.annotation.Reference;
import com.rabbitmq.client.ConnectionFactory;
import com.test.bean.M2SInfo;
import com.test.bean.MenuInfo;
import com.test.service.IMenuService;
@Component
public class CrontabGetMsg {
@Autowired
private AmqpTemplate amqp;
@Reference(check=false)
private IMenuService serv;
//秒 分 时 日 月 周 年
//每五秒接收一次消息
@Scheduled(cron="0/5 * * ? * *")
public void getMsg()
{
//System.out.println("getMsg() "+new java.sql.Timestamp(System.currentTimeMillis()));
try
{
Message msg = amqp.receive(RabbitmqConf.QUEUE1);
if(msg == null)
return;
byte[] data = msg.getBody();
Object obj = toObject(data);
if(obj instanceof MenuInfo)
{
MenuInfo mi = (MenuInfo)obj;
String sid = mi.getSid();
Integer id = mi.getId();
System.out.println("getMsg id="+id+",name="+mi.getName()+",sid="+sid);
if(id == null)//新增
{
mi = serv.saveMenu(mi);
System.out.println("saveMenu genId = "+mi.getId());
}
else//更新
{
serv.updateMenu(mi);
//删除原来关联中间表数据
serv.deleteM2S(mi.getId());
}
String[] dim = sid.split(",");
for(String sid2:dim)
{
M2SInfo m2s = new M2SInfo();
m2s.setSid(new Integer(sid2));
m2s.setMid(mi.getId());
serv.saveM2S(m2s);
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
public Object toObject(byte[] data)
{
try
{
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais);
Object obj = ois.readObject();
bais.close();
return obj;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
消息监听器
package com.test.util;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.test.bean.M2SInfo;
import com.test.bean.MenuInfo;
import com.test.service.IMenuService;
@Component
public class RabbitmqListener {
@Autowired
private IMenuService serv;
@RabbitListener(queues="test_queue1")
public void receive(Message msg)
{
try
{
byte[] data = msg.getBody();
Object obj = toObject(data);
if(obj instanceof MenuInfo)
{
MenuInfo mi = (MenuInfo)obj;
String sid = mi.getSid();
Integer id = mi.getId();
System.out.println("getMsg id="+id+",name="+mi.getName());
if(id == null)//新增
{
serv.saveMenu(mi);
}
else//更新
{
serv.updateMenu(mi);
//删除原来关联中间表数据
serv.deleteM2S(mi.getId());
}
String[] dim = sid.split(",");
for(String sid2:dim)
{
M2SInfo m2s = new M2SInfo();
m2s.setSid(new Integer(sid2));
m2s.setMid(mi.getId());
serv.saveM2S(m2s);
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
public Object toObject(byte[] data)
{
try
{
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais);
Object obj = ois.readObject();
bais.close();
return obj;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
RabbitMq配置类,配置交换机与队列
package com.test.util;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitmqConf {
public static String QUEUE1 = "test_queue1";
public static String EXCHANGE1 = "test_exg1";
@Bean
public Queue queue1()
{
return new Queue(QUEUE1);
}
@Bean
public DirectExchange exg1()
{
return new DirectExchange(EXCHANGE1);
}
@Bean
public Binding directBinding1() {
return BindingBuilder.bind(queue1()).to(exg1()).with("java");
}
}
编写分页工具类
package com.test.util;
public class PageUtil {
private Integer page = 1;//默认显示第一页
private Integer rows = 4;//每页显示记录数
private Long total = null;//总行数
private String url = null;//点击页码跳转url
public PageUtil(String url,Integer page,Integer rows,Long total)
{
this.url = url;
this.page = page;
this.rows = rows;
this.total = total;
}
public String toHtml()
{
StringBuffer sb = new StringBuffer();
//计算总页数
int pages = 0;
if(total % rows == 0)
pages = total.intValue() / rows;
else
pages = (total.intValue() / rows) + 1;
sb.append("<div id='pagediv'>\r\n");
String firstUrl = null;
if(url.indexOf("?")>0)
firstUrl = url + "&page=1&rows="+rows;
else
firstUrl = url + "?page=1&rows="+rows;
sb.append("<a href='"+firstUrl+"'>首页</a>\r\n");
String backUrl = null;
if(url.indexOf("?")>0)
backUrl = url + "&page="+(page==1?1:(page-1))+"&rows="+rows;
else
backUrl = url + "?page="+(page==1?1:(page-1))+"&rows="+rows;
sb.append("<a href='"+backUrl+"'>上一页</a>\r\n");
for(int i=1;i<=pages;i++)
{
String pageUrl = null;
if(url.indexOf("?")>0)
pageUrl = url + "&page="+i+"&rows="+rows;
else
pageUrl = url + "?page="+i+"&rows="+rows;
if(i == page)
sb.append("<a href='"+pageUrl+"'><b><font color='red'>"+i+"</font></b></a>\r\n");
else
sb.append("<a href='"+pageUrl+"'>"+i+"</a>\r\n");
}
String nextUrl = null;
if(url.indexOf("?")>0)
nextUrl = url + "&page="+(page==pages?pages:(page+1))+"&rows="+rows;
else
nextUrl = url + "?page="+(page==pages?pages:(page+1))+"&rows="+rows;
sb.append("<a href='"+nextUrl+"'>下一页</a>\r\n");
String lastUrl = null;
if(url.indexOf("?")>0)
lastUrl = url + "&page="+pages+"&rows="+rows;
else
lastUrl = url + "?page="+pages+"&rows="+rows;
sb.append("<a href='"+lastUrl+"'>尾页</a>\r\n");
sb.append(" 第"+page+"/"+pages+"页\r\n");
sb.append(" 共"+total+"条记录\r\n");
sb.append("</div>\r\n");
return sb.toString();
}
}
菜单页面
<%@ 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" type="text/css" href="/js/base.css">
<script type="text/javascript" src="/js/jquery.min.js"></script>
<script>
function doquery()
{
listfrm.submit();
}
function dodelete()
{
listfrm.action = '/delete'
listfrm.submit();
}
function selectall()
{
$('input[name="id"]').each(function(){
this.checked = $('#idall').prop("checked");
})
}
function doadd()
{
var url = '/add';
window.open(url,'_self');
}
function doedit(id)
{
var url = '/modify?id='+id;
window.open(url,'_self');
}
function doview(id)
{
var url = '/view?id='+id;
window.open(url,'_self');
}
function dorefresh()
{
var url = '/list';
window.open(url,'_self');
}
function dosingledel(id)
{
listfrm.action = '/delete?id='+id
listfrm.submit();
}
</script>
</head>
<body>
<form id="listfrm" action="/list" method="post">
<input type="text" id="name" name="name" value="${name }"/>
<input type="button" onclick="doquery()" value="查询"/>
<input type="button" onclick="dodelete()" value="批量删除"/>
<input type="button" onclick="doadd()" value="添加"/>
<input type="button" onclick="dorefresh()" value="刷新"/>
<table>
<tr>
<th><input type="checkbox" id="idall" name="idall" onclick="selectall()">全选</th>
<th>编号</th>
<th>名称</th>
<th>材料</th>
<th>价格</th>
<th>操作</th>
</tr>
<c:forEach items="${menuList}" var="m">
<tr>
<td><input type="checkbox" id="id" name="id" value="${m.id }"></td>
<td>${m.id }</td>
<td>${m.name }</td>
<td>${m.sname }</td>
<td>${m.price }</td>
<td>
<input type="button" value="编辑" onclick="doedit(${m.id })"/>
<input type="button" value="查看" onclick="doview(${m.id })"/>
<input type="button" value="删除" onclick="dosingledel(${m.id })"/>
</td>
</tr>
</c:forEach>
</table>
${pageDiv }
</form>
</body>
</html>
添加页面
<%@ 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" type="text/css" href="/js/base.css">
<script type="text/javascript" src="/js/jquery.min.js"></script>
<script>
function dosave()
{
addfrm.submit();
}
</script>
</head>
<body>
<form id="addfrm" action="/save" method="post">
<table>
<input type="hidden" id="id" name="id" value="${menu.id}"/>
<tr>
<td>菜单名称</td>
<td><input type="text" id="name" name="name" value="${menu.name}"/></td>
</tr>
<tr>
<td>价格</td>
<td><input type="text" id="price" name="price" value="${menu.price}"/></td>
</tr>
<tr>
<td>材料</td>
<td>
<c:forEach items="${staffList }" var="s">
<input type="checkbox" id="sid" name="sid" value="${s.id }" ${s.checked}>${s.name}
</c:forEach>
</td>
</tr>
</table>
<input type="button" onclick="dosave()" value="保存">
<input type="button" onclick="window.open('/list','_self')" value="返回">
</form>
</body>
</html>
查看页面
<%@ 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" type="text/css" href="/js/base.css">
<script type="text/javascript" src="/js/jquery.min.js"></script>
<script>
function dosave()
{
addfrm.submit();
}
</script>
</head>
<body>
<form id="addfrm" action="/save" method="post">
<table>
<input type="hidden" id="id" name="id" value="${menu.id}"/>
<tr>
<td>菜单名称</td>
<td><input type="text" id="name" name="name" value="${menu.name}"/></td>
</tr>
<tr>
<td>价格</td>
<td><input type="text" id="price" name="price" value="${menu.price}"/></td>
</tr>
<tr>
<td>材料</td>
<td>
<c:forEach items="${staffList }" var="s">
<input type="checkbox" id="sid" name="sid" value="${s.id }" ${s.checked}>${s.name}
</c:forEach>
</td>
</tr>
</table>
<input type="button" onclick="window.open('/list','_self')" value="返回">
</form>
</body>
</html>
通用CSS
@charset "utf-8";
/* CSS Document */
body{
margin:0 auto;
padding:0;
font-family:'Microsoft YaHei', arial, tahoma, \5b8b\4f53, sans-serif;
font-size: 14px;
}
a {
text-decoration:none;
color:black;
}
div{
margin:0 auto;
}
#pagediv{
margin:0 auto;
text-align:center;
valign:middle;
background-color: yellow;
height:30px;
line-height: 30px;
border:1px solid black
}
table {
width:100%;
font-family: verdana,arial,sans-serif;
font-size:11px;
color:#333333;
border-width: 1px;
border-color: #666666;
border-collapse: collapse;
}
table tr:nth-child(odd) td{
background: #ccc;
}
table tr:hover td{
background: pink;
}
table th {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
background-color: yellow;
}
table th {
font-size:15px;
color:blue;
}
table td {
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #666666;
background-color: #ffffff;
}
Web项目的SpringBoot启动类
package com.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
@SpringBootApplication
@EnableDubboConfiguration
public class Starter extends SpringBootServletInitializer{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application){
return application.sources(Starter.class);
}
public static void main(String[] args) {
SpringApplication.run(Starter.class, args);
}
}
启动Web项目
测试效果
代码下载
Dubbo Service 代码:https://github.com/qixiangchen/Menu_DubboService.git
Web 代码:https://github.com/qixiangchen/Menu_DubboWeb.git