前言:由于導師在我的畢設項目里加了消息系統(tǒng)(本來想水水就過的..)蔓罚,沒辦法...來稍微研究研究吧..簡單簡單...
需求分析
我的畢設是一個博客系統(tǒng),類似于簡書這樣的瞻颂,所以消息系統(tǒng)也類似豺谈,在用戶的消息里包含了有:喜歡和贊、評論贡这、關注茬末、私信這樣的一類東西,這樣的一個系統(tǒng)應該包含以下的功能:
-
- 當用戶評論/關注/點贊時能夠通知到被評論/關注/點贊的用戶盖矫,并生成像如下格式的提示信息(允許取消關注/點贊但不收到通知):
我沒有 關注了 你
三顆 喜歡了你的文章 《Java消息系統(tǒng)簡單設計與實現(xiàn)》
心臟 評論了你的文章 《Java消息系統(tǒng)簡單設計與實現(xiàn)》 - 用戶之間能夠發(fā)送/接受私信丽惭,不需要像QQ那樣建立長連接實現(xiàn)實時通信,但刷新列表能看到新消息辈双,并且界面類似QQ聊天界面一左一右责掏,允許刪除私信;
- 管理員能發(fā)送通告湃望,其實就像是用管理員的賬號給每一個用戶發(fā)送私信换衬;
- 可以查看關注的用戶最新發(fā)表的文章,得到類似推送的效果证芭;
- 所有消息當然也要標注好消息已讀or未讀瞳浦,登錄就能得到消息提醒標識好有多少未讀消息,像是QQ消息右上角的小紅點那樣類似废士;
OK叫潦,大致就是以上的功能,那么問題來了:這要怎么設計肮傧酢矗蕊?
進一步分析
其實可以根據(jù)上面的需求分析,把上面的消息大致可以分為公告(Announcement)氢架、提醒(Remind)拔妥、私信(Message)三類,我們可以大致抽象出一個 通知(Notify) 模型:
發(fā)送者 | 接受者 | 信息類型 | 動作類型 | 通知內(nèi)容 | 是否已讀 | 消息創(chuàng)建時間 |
---|---|---|---|---|---|---|
粉絲1號 | 我沒有三顆心臟 | 提醒 | 關注 | 粉絲1號 關注了 你 | 是 | xx:xx:xx |
粉絲1號 | 我沒有三顆心臟 | 提醒 | 喜歡和贊 | 粉絲1號 喜歡了你的文章 《Java消息系統(tǒng)簡單設計與實現(xiàn)》 | 是 | xx:xx:xx |
粉絲1號 | 我沒有三顆心臟 | 提醒 | 評論 | 粉絲1號 評論了你的文章 《Java消息系統(tǒng)簡單設計與實現(xiàn)》 | 是 | xx:xx:xx |
粉絲2號 | 我沒有三顆心臟 | 私信 | 無 | 你收到了來自 粉絲2號 的 1 條私信 | 是 | xx:xx:xx |
上面加了一些數(shù)據(jù)以便理解达箍,不過話說粉絲1號果然是真愛粉没龙,又關注又喜歡又評論,嘻嘻嘻嘻...
emm.這樣的模型能夠勝任我們的工作嗎缎玫?我也不知道..不過根據(jù)這個模型能夠想出大概的這樣的創(chuàng)建通知的邏輯:
似乎看上去也沒有什么大問題..不過既然消息內(nèi)容都可以根據(jù)動作類型自動生成的了硬纤,加上私信和公告的內(nèi)容因為長度問題也肯定不保存在這張表里的好,所以我們在設計數(shù)據(jù)庫時干脆把通知內(nèi)容這條去掉不要赃磨,當信息類型是公告或者私信時可以根據(jù)這條通知的 id 在相應的表中找到相應的數(shù)據(jù)就可以了筝家,emm..我覺得可以
順下去想想其實腦中有了一個大概,這樣的模型還容易設計和想到邻辉,其實主要的問題還是下面的那些
問題一:單表數(shù)據(jù)大了怎么辦溪王?
如果當用戶量上去到一定量的時候腮鞍,那么這張 通知表 勢必會變得巨大,因為不管是我們的公告莹菱、提醒還是私信都會在這個通知表上創(chuàng)建一條數(shù)據(jù)移国,到時候就會面臨查詢慢的問題,問題的答案是:我也不知道..
所以我們的規(guī)定是:不考慮像簡書這樣超大用戶量道伟,能夠應付畢設就好啦..簡單設計迹缀,嘻嘻嘻..不過也不要太不相信MySQL的性能,還是有一定容納能力的蜜徽!
問題二:用戶要怎樣正確得到自己的未讀消息呢祝懂?
暴力一點方法是,反正通知表里有用戶所有的消息拘鞋,直接讀取完忘巧,然后通過是否已讀字段就能夠找到正確的所有未讀消息了习勤,這..這么簡單嗎谴忧?
其實有思考過使用時間或者另建一張保存有最新已讀到哪條消息的表汞贸,但用戶可以選擇有一些讀有一些不讀虾宇,這兩個似乎都很難達到目的...還是暴力吧
問題三:私信消息該怎么設計元莫?
發(fā)送者 | 接受者 | 內(nèi)容 | 發(fā)送時間 |
---|---|---|---|
粉絲1號 | 我沒有三顆心臟 | 我是你的真愛粉鞍饨恕宪郊!我要給你生猴子峡扩! | 2019年1月7日11:34:23 |
我沒有三顆心臟 | 粉絲1號 | 已閱...下一個... | 2019年1月7日11:34:53 |
就像 QQ消息 一樣嘛蹭越,包含一個內(nèi)容、時間教届、發(fā)送者和接受者响鹃,然后前端直接根據(jù)時間或者 id 排序生成一左一右的消息對話框,不過比較特殊的一點就是私信是一個雙向交流的過程案训,在一個對話框中我可能既是接受者也是發(fā)送者买置,這也無所謂嘛,稍微分析分析場景:
- 讀取私信列表時:按照接受者和發(fā)送者一起查詢的原則强霎,也就是查詢接受者是自己和發(fā)送者是自己的數(shù)據(jù)忿项,然后根據(jù)時間和已讀未讀來建立私信列表;
- 讀取私信時:這時已經(jīng)有了明確的接受者和發(fā)送者城舞,那就查詢所有 發(fā)送者是對方接受者是自己 Or 發(fā)送者是自己接受者是對方 的數(shù)據(jù)轩触,然后在前端拼湊出一左一右的聊天框;
- 發(fā)送私信時:先查詢之前是否有記錄家夺,然后同上建立聊天框脱柱,點擊發(fā)送之后把發(fā)送方設為自己接收方設為私信對象,然后在通知表中新建一條未讀數(shù)據(jù)通知私信對象有私信來了拉馋;
這完全能滿足要求榨为,只不過感覺查詢多了些..
數(shù)據(jù)庫設計
簡單弄了弄弄..看著挺難受的惨好,不過能簡單實現(xiàn)功能,并且為了演示随闺,這里是做了一張user_follow表日川,表示用戶之間的關聯(lián)關系,點贊和評論與這個類似板壮,就不多弄了..下面給一下建表語句吧:
user表:
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`username` varchar(50) NOT NULL COMMENT '用戶姓名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
user_follow表:
CREATE TABLE `user_follow` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`uid` bigint(20) NOT NULL COMMENT '用戶ID',
`follow_uid` bigint(20) NOT NULL COMMENT '關注的用戶id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶關注表,記錄了所有用戶的關注信息';
notify表:
CREATE TABLE `notify` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`sender_id` bigint(20) NOT NULL COMMENT '發(fā)送者用戶ID',
`reciver_id` bigint(20) NOT NULL COMMENT '接受者用戶ID',
`type` varchar(50) NOT NULL COMMENT '消息類型:announcement公告/remind提醒/message私信',
`is_read` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否已讀,0未讀,1已讀',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間:按當前時間自動創(chuàng)建',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶通知表,包含了所有用戶的消息';
message表:
CREATE TABLE `message` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`notify_id` bigint(20) NOT NULL COMMENT '對應通知消息的id',
`sender_id` bigint(20) NOT NULL COMMENT '發(fā)送者用戶ID',
`reciver_id` bigint(20) NOT NULL COMMENT '接受者用戶ID',
`content` varchar(1000) NOT NULL COMMENT '消息內(nèi)容,最長長度不允許超過1000',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間:按當前時間自動創(chuàng)建',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='私信信息表,包含了所有用戶的私信信息';
根據(jù)《Java開發(fā)手冊》5.3 第六條 沒有使用任何級聯(lián)和外鍵逗鸣,bingo!
Spring Boot + MyBatis 實例
第一步:基礎環(huán)境搭建
SpringBoot項目怎么搭就不說了吧绰精,給一給幾個關鍵的配置文件:
pom包依賴:
<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.2</version>
</dependency>
<!-- SpringBoot - MyBatis 逆向工程 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>5.1.18</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
這里有一個巨坑撒璧,耗費了我好半天的時間,不知道為什么我明明引入的 5.1.18 版本的 mysql-connector-java笨使,可 Maven 就是非要給我比較新版本的 8.0.13卿樱,這導致了在我使用 MyBatis 逆向工程生成 domain 和 mapper 的過程中出現(xiàn)了以下的問題:
- 1、提示我數(shù)據(jù)庫連接的驅動名稱需要改成
com.mysql.cj.jdbc.Driver
而不是之前的com.mysql.jdbc.Driver
硫椰,不然就報錯:
Loading class
com.mysql.jdbc.Driver'. This is deprecated. The new driver class is
com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
- 2繁调、還需要設置 mysql 的時區(qū),也就是需要將
connectionURL
屬性寫成"jdbc:mysql://localhost:3306/test?serverTimezone=UTC"
靶草。如果不指定serverTimezone=UTC(還必須大寫)蹄胰,將報錯:
java.sql.SQLException: The server time zone value '?й???????' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
??at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:695)
??at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:663)
- 3、逆向工程會去找 MySQL 其他庫的相同表名的表奕翔,然后生成一堆亂七八糟的東西裕寨,還由于找不到主鍵 id 生成了只含
inser()
方法而不含刪除、更新方法的 Mapper 文件派继;
解決方法就只有自己手動去調低 mysql-connector-java 的版本到 5.xx宾袜,還找到一個跟我情況類似:https://blog.csdn.net/angel_xiaa/article/details/52474022
application.properties:
## 數(shù)據(jù)庫連接配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/message_system?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
## MyBatis相關配置
mybatis.type-aliases-package=com.wmyskxz.demo.messagesystem.domain
mybatis.mapper-locations=classpath:mapper/*.xml
在啟動類上加上注解:
@EnableTransactionManagement // 啟注解事務管理,等同于xml配置方式的 <tx:annotation-driven />
@MapperScan("com.wmyskxz.demo.messagesystem.dao")
@SpringBootApplication
public class MessageSystemApplication {
....
}
第二步:MyBatis 逆向工程
新建【util】包驾窟,在下面新建兩個類:
MybatisGenerator類:
public class MybatisGenerator {
public static void main(String[] args) throws Exception {
String today = "2019-1-7";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date now = sdf.parse(today);
Date d = new Date();
if (d.getTime() > now.getTime() + 1000 * 60 * 60 * 24) {
System.err.println("——————未成成功運行——————");
System.err.println("——————未成成功運行——————");
System.err.println("本程序具有破壞作用庆猫,應該只運行一次,如果必須要再運行绅络,需要修改today變量為今天月培,如:" + sdf.format(new Date()));
return;
}
if (false)
return;
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
InputStream is = MybatisGenerator.class.getClassLoader().getResource("generatorConfig.xml").openStream();
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(is);
is.close();
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
System.out.println("生成代碼成功,只能執(zhí)行一次恩急,以后執(zhí)行會覆蓋掉mapper,pojo,xml 等文件上做的修改");
}
}
OverIsMergeablePlugin類:
/**
* 解決 MyBatis 逆向工程重復生成覆蓋問題的工具類
*/
public class OverIsMergeablePlugin extends PluginAdapter {
@Override
public boolean validate(List<String> warnings) {
return true;
}
@Override
public boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {
try {
Field field = sqlMap.getClass().getDeclaredField("isMergeable");
field.setAccessible(true);
field.setBoolean(sqlMap, false);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
}
在【resrouces】資源文件下新建逆向工程配置文件【generatorConfig.xml】:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!--避免生成重復代碼的插件-->
<plugin type="com.wmyskxz.demo.messagesystem.util.OverIsMergeablePlugin"/>
<!-- 是否去除自動生成的代碼中的注釋 true:是 false:否-->
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--數(shù)據(jù)庫鏈接地址賬號密碼-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/message_system?serverTimezone=UTC"
userId="root" password="123456">
</jdbcConnection>
<!-- 默認 false节视,把 JDBC DECIMAL 和 NUMERIC 類型解析為 Integer
為 true 時解析為 java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!--生成pojo類存放位置-->
<javaModelGenerator targetPackage="com.wmyskxz.demo.messagesystem.domain" targetProject="src/main/java">
<!-- enableSubPackages:是否讓 schema 作為包的后綴-->
<property name="enableSubPackages" value="true"/>
<!-- trimStrings:從數(shù)據(jù)庫返回的值被清理前后的空格 -->
<property name="trimStrings" value="true"/>
<!-- 是否對model添加 構造函數(shù) -->
<property name="constructorBased" value="true"/>
</javaModelGenerator>
<!--生成xml映射文件存放位置-->
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!--生成mapper類存放位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.wmyskxz.demo.messagesystem.dao"
targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!--生成對應表及類名
tableName:要生成的表名
domainObjectName:生成后的實例名
enableCountByExample:Count語句中加入where條件查詢,默認為true開啟
enableUpdateByExample:Update語句中加入where條件查詢假栓,默認為true開啟
enableDeleteByExample:Delete語句中加入where條件查詢寻行,默認為true開啟
enableSelectByExample:Select多條語句中加入where條件查詢,默認為true開啟
selectByExampleQueryId:Select單個對象語句中加入where條件查詢匾荆,默認為true開啟
-->
<table tableName="user" domainObjectName="User" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false" enableDeleteByPrimaryKey="true" enableUpdateByPrimaryKey="true">
<property name="my.isgen.usekeys" value="true"/>
<property name="useActualColumnNames" value="false"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="notify" domainObjectName="Notify" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false" enableDeleteByPrimaryKey="true" enableUpdateByPrimaryKey="true">
<property name="my.isgen.usekeys" value="true"/>
<property name="useActualColumnNames" value="false"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="user_follow" domainObjectName="UserFollow" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false" enableDeleteByPrimaryKey="true" enableUpdateByPrimaryKey="true">
<property name="my.isgen.usekeys" value="true"/>
<property name="useActualColumnNames" value="false"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<table tableName="message" domainObjectName="Message" enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
selectByExampleQueryId="false" enableDeleteByPrimaryKey="true" enableUpdateByPrimaryKey="true">
<property name="my.isgen.usekeys" value="true"/>
<property name="useActualColumnNames" value="false"/>
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
</context>
</generatorConfiguration>
運行我們的【MybatisGenerator】類中的 main 方法就能看到自動生成的實體拌蜘、Xml文件以及 Mapper 類
第三步:Service 層
不給接口了杆烁,直接給實現(xiàn)吧,方法都很簡單简卧,而且沒有做任何的安全限制兔魂,只是為了實現(xiàn)簡單的消息系統(tǒng),看效果
UserServiceImpl:
@Service
public class UserServiceImpl implements UserService {
@Resource
UserMapper userMapper;
@Override
public void addUserByUsername(String username) {
userMapper.insert(new User(null, username));// 主鍵自增長.
}
@Override
public User findUserById(Long id) {
return userMapper.selectByPrimaryKey(id);
}
}
UserFollowServiceImpl:
@Service
public class UserFollowServiceImpl implements UserFollowService {
@Resource
UserFollowMapper userFollowMapper;
@Autowired
NotifyService notifyService;
@Override
public void userAFollowUserBById(Long userAId, Long userBId) {
// 先要創(chuàng)建一條提示消息
notifyService.addNotify(userAId, userBId, "follow");// 關注信息
UserFollow userFollow = new UserFollow();
userFollow.setUid(userAId);
userFollow.setFollowUid(userBId);
userFollowMapper.insertSelective(userFollow);
}
@Override
public void userAUnfollowUserBById(Long userAId, Long userBId) {
// 首先查詢到相關的記錄
UserFollowExample example = new UserFollowExample();
example.or().andUidEqualTo(userAId).andFollowUidEqualTo(userBId);
UserFollow userFollow = userFollowMapper.selectByExample(example).get(0);
// 刪除關注數(shù)據(jù)
userFollowMapper.deleteByPrimaryKey(userFollow.getId());
}
}
NotifyServiceImpl:
@Service
public class NotifyServiceImpl implements NotifyService {
@Resource
NotifyMapper notifyMapper;
@Override
public int addNotify(Long senderId, Long reciverId, String type) {
Notify notify = new Notify(null, senderId, reciverId, type, false, null);
return notifyMapper.insertSelective(notify);// id和creatTime自動生成.
}
@Override
public void readNotifyById(Long id) {
Notify notify = notifyMapper.selectByPrimaryKey(id);
notify.setIsRead(true);
notifyMapper.updateByPrimaryKey(notify);
}
@Override
public List<Notify> findAllNotifyByReciverId(Long id) {
List<Notify> notifies = new LinkedList<>();
NotifyExample example = new NotifyExample();
example.setOrderByClause("`id` DESC");// 按id倒敘,也就是第一個數(shù)據(jù)是最新的.
example.or().andReciverIdEqualTo(id);
notifies.addAll(notifyMapper.selectByExample(example));
return notifies;
}
@Override
public List<Notify> findAllUnReadNotifyByReciverId(Long id) {
List<Notify> notifies = new LinkedList<>();
NotifyExample example = new NotifyExample();
example.setOrderByClause("`id` DESC");// 按id倒敘,也就是第一個數(shù)據(jù)是最新的.
example.or().andReciverIdEqualTo(id).andIsReadEqualTo(false);
notifies.addAll(notifyMapper.selectByExample(example));
return notifies;
}
}
MessageServiceImpl:
@Service
public class MessageServiceImpl implements MessageService {
@Resource
MessageMapper messageMapper;
@Resource
NotifyService notifyService;
@Override
public void addMessage(Long senderId, Long reciverId, String content) {
// 先創(chuàng)建一條 notify 數(shù)據(jù)
Long notifyId = (long) notifyService.addNotify(senderId, reciverId, "message");// message表示私信
// 增加一條私信信心
Message message = new Message(null, notifyId, senderId, reciverId, content, null);
messageMapper.insertSelective(message);// 插入非空項,id/createTime數(shù)據(jù)庫自動生成
}
@Override
public void deleteMessageById(Long id) {
messageMapper.deleteByPrimaryKey(id);
}
@Override
public Message findMessageByNotifyId(Long id) {
// 觸發(fā)方法時應把消息置為已讀
notifyService.readNotifyById(id);
MessageExample example = new MessageExample();
example.or().andNotifyIdEqualTo(id);
return messageMapper.selectByExample(example).get(0);
}
}
第四步:Controller 層
也很簡單举娩,只是為了看效果
UserController:
@RestController
public class UserController {
@Autowired
UserService userService;
@PostMapping("/addUser")
public String addUser(@RequestParam String username) {
userService.addUserByUsername(username);
return "Success!";
}
@GetMapping("/findUser")
public User findUser(@RequestParam Long id) {
return userService.findUserById(id);
}
}
UserFollowController :
@RestController
public class UserFollowController {
@Autowired
UserFollowService userFollowService;
@PostMapping("/follow")
public String follow(@RequestParam Long userAId,
@RequestParam Long userBId) {
userFollowService.userAFollowUserBById(userAId, userBId);
return "Success!";
}
@PostMapping("/unfollow")
public String unfollow(@RequestParam Long userAId,
@RequestParam Long userBId) {
userFollowService.userAUnfollowUserBById(userAId, userBId);
return "Success!";
}
}
NotifyController :
@RestController
public class NotifyController {
@Autowired
NotifyService notifyService;
@PostMapping("/addNotify")
public String addNotify(@RequestParam Long senderId,
@RequestParam Long reciverId,
@RequestParam String type) {
notifyService.addNotify(senderId, reciverId, type);
return "Success!";
}
@PostMapping("/readNotify")
public String readNotify(@RequestParam Long id) {
notifyService.readNotifyById(id);
return "Success!";
}
@GetMapping("/listAllNotify")
public List<Notify> listAllNotify(@RequestParam Long id) {
return notifyService.findAllNotifyByReciverId(id);
}
@GetMapping("/listAllUnReadNotify")
public List<Notify> listAllUnReadNotify(@RequestParam Long id) {
return notifyService.findAllUnReadNotifyByReciverId(id);
}
}
MessageController :
@RestController
public class MessageController {
@Autowired
MessageService messageService;
@PostMapping("/addMessage")
public String addMessage(@RequestParam Long senderId,
@RequestParam Long reciverId,
@RequestParam String content) {
messageService.addMessage(senderId, reciverId, content);
return "Success!";
}
@DeleteMapping("/deleteMessage")
public String deleteMessage(@RequestParam Long id) {
messageService.deleteMessageById(id);
return "Success!";
}
@GetMapping("/findMessage")
public Message findMessage(@RequestParam Long id) {
return messageService.findMessageByNotifyId(id);
}
}
第五步:測試
通過 REST 測試工具析校,可以看到正確的效果,這里就不給出所有的測試了铜涉。
總結
以上的項目簡單而且沒有任何的安全驗證智玻,不過能夠基本完成我們的需求,還有一些功能沒有實現(xiàn)芙代,例如管理員發(fā)通告(上面只演示了私信和關注信息)吊奢,按照上面的系統(tǒng)就直接暴力給每個用戶都加一條通知消息,感覺有點自閉..我也不知道怎么設計好..希望有經(jīng)驗的大大能指條路拔婆搿页滚!
其實關于這個簡單的系統(tǒng)我查了好多好多資料..把自己都看自閉了,后來我干脆把所有網(wǎng)頁都關掉铺呵,開始用 JPA 自己開始抽象實體裹驰,把各個實體寫出來并把所有實體需要的數(shù)據(jù)啊相互之間的關聯(lián)關系啊寫清楚,然后再從自動生成的數(shù)據(jù)庫中找思路...hhh...要不是我 JPA 不是很熟我覺得用 JPA 就能寫出來了片挂,不用 JPA 的原因在于一些數(shù)據(jù)的懶加載不知道怎么處理幻林,還有就是查詢語句太復雜,免不了要浪費一些資源...emmm..說到底還是不是特別懂 JPA宴卖,下面給一張復雜的用 JPA 建立的 User 實體吧(隨手截的..hhh...很亂..):
按照慣例黏一個尾巴:
歡迎轉載滋将,轉載請注明出處邻悬!
簡書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關注公眾微信號:wmyskxz
分享自己的學習 & 學習資料 & 生活
想要交流的朋友也可以加qq群:3382693