首先得将自己的qq开启qq邮箱的POP3/SMTP服务

说明:

p,e为路由key。

用户系统完成登录的时候,将{手机号-时间-IP}保存到队列Phone-queue中,msg-sys系统获得消息打印到控制台(完成用户登录过程短信服务的异步调用,完成用户系统和短信系统的解耦合)

用户系统完成注册的时候,将{email-时间-IP-账户激活url }保存到队列email-sys中,email-sys将消息打印到控制台,使用控制台打印的账户激活的url,在浏览器向user-sys系统发送请求,修改user表中locked字段的值。(完成用户注册过程邮件服务的异步调用,完成用户系统和邮件系统的解耦合),修改完成后给用户提示账户激活成功

用户登录

用户登录的时候提交用户名和密码,然后给用户短信提示,用户在什么时间,用哪个IP,进行登录。需要将电话-时间-IP格式的数据保存到队列中

用户注册

用户注册,用户注册后,给用户注册信息进行邮箱的激活,点击哪个url进行账户激活。修改数据库中locked字段的值。需要将Email-时间-URL格式的数据保存到队列中

当我们点击注册的时候,会向消息队列发送注册信息,以及向qq邮箱发送文件激活的url

然后看pom文件

<?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.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>spring-boot-jpa-dlzc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-jpa-dlzc</name>
<description>spring-boot-jpa-dlzc</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</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.47</version>
</dependency> <!--开启QQ邮箱验证-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!-- rabbitmq -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

由于此项目用到了消息队列

因此注意项目奖结构

消息的发送者    spring-boot-jpa-dlzc

application.properties配置文件

#Mysql数据源配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/sys?characterEncoding=UTF8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root #JPA相关配置
#项目启动生成数据库
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true server.port=8081
spring.rabbitmq.host=192.168.181.134
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=111111 #设置交换器的名称
mq.config.exchange=log.direct #设置短信的路由键
mq.config.queue.message.routing.key=log.message.routing.key #设置邮件的路由键
mq.config.queue.email.routing.key=log.email.routing.key #qq邮箱的规则
spring.mail.host=smtp.qq.com
spring.mail.username=设置申请邮箱的账号
spring.mail.password=邮箱的验证码
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true

实体类

locked字段是为了激活账号使用的,给予默认值是0,注册成但是未激活的时候,此时locked值是0,点击激活之后locked值修改成1,在我们登录的时候带着uname和pwd以及locked的值为1三个条件去判断,如果有值说明账户激活成功,查询没有则返回用户,账户未激活信息提示

package com.bjsxt.pojo;

import lombok.Data;
import org.hibernate.annotations.ColumnDefault; import javax.persistence.*;
import java.io.Serializable; @Entity
@Table(name = "users")
@Data
public class Users implements Serializable { @Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "uid")
private int uid; @Column(name = "uname")
private String uname; @Column(name = "pwd")
private String pwd; @Column(name = "email")
private String email; @Column(name = "phone")
private String phone; @Column(name = "locked")
@ColumnDefault(value = "0")
private int locked; public Users() {
} public Users(String uname, String pwd, String email, String phone, int locked) {
this.uname = uname;
this.pwd = pwd;
this.email = email;
this.phone = phone;
this.locked = locked;
}
}

消息发送实现类

com.bjsxt.send.LoginSender

package com.bjsxt.send;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; /***
* 消息的发送者
*/
@Component
public class LoginSender { @Autowired
private AmqpTemplate amqpTemplate; @Value("${mq.config.exchange}")
private String exchange; @Value("${mq.config.queue.message.routing.key}")
private String routingkey; /**
* 发送消息的方法
* @param msg
*/
public void sendMsg(String msg){
/*向消息队列发送消息*/
/*
* 参数一:队列的名称
* 参数二:发送的消息
* */
amqpTemplate.convertAndSend(exchange,routingkey,msg); }
}

com.bjsxt.send.RegSender

package com.bjsxt.send;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; /***
* 消息的发送者
*/
@Component
public class RegSender { @Autowired
private AmqpTemplate amqpTemplate; @Value("${mq.config.exchange}")
private String exchange; @Value("${mq.config.queue.email.routing.key}")
private String routingkey; /**
* 发送消息的方法
* @param msg
*/
public void sendMsg(String msg){
/*向消息队列发送消息*/
/*
* 参数一:队列的名称
* 参数二:发送的消息
* */
amqpTemplate.convertAndSend(exchange,routingkey,msg); }
}

dao层

com.bjsxt.dao.UserDao

package com.bjsxt.dao;

import com.bjsxt.pojo.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional; public interface UserDao extends JpaRepository<Users,Integer>, JpaSpecificationExecutor<Users> { /**
* 登录操作
* @param uname
* @param pwd
* @return
*/
@Query(value = "select * from users where uname=? and pwd =? and locked=1",nativeQuery = true)
Users findUser(String uname,String pwd); /**
* 激活操作
* @param uid
*/
@Modifying
@Transactional
@Query(value = "update users set locked=1 where uid=?",nativeQuery = true)
void updateUser(int uid); /**
* 激活操作
* @param uname
* @param pwd
*/
@Modifying
@Transactional
@Query(value = "update users set locked=1 where uname=? and pwd =?",nativeQuery = true)
void updateUserlocked(String uname,String pwd); }

service层

com.bjsxt.service.UserService(接口)

package com.bjsxt.service;

import com.bjsxt.pojo.Users;

public interface UserService {
/**
* 添加用户
* @param users
*/
void addUser(Users users); /**
* 处理登录请求
* @param uname
* @param pwd
* @return
*/
Users findUser(String uname,String pwd); /***
* 处理用户激活
* @param uid
* @return
*/
void updateUserLock(int uid); /**
* 处理用户激活
* @param uname
* @param pwd
*/
void updateLock(String uname,String pwd);
}

com.bjsxt.service.impl.UserServiceImpl接口实现类

package com.bjsxt.service.impl;

import com.bjsxt.dao.UserDao;
import com.bjsxt.pojo.Users;
import com.bjsxt.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; @Service
public class UserServiceImpl implements UserService { @Autowired
private UserDao userDao; /**
* 添加用户操作
* @param users
*/
@Override
public void addUser(Users users) {
userDao.save(users);
} /**
* 处理登录操作
* @param uname
* @param pwd
* @return
*/
@Override
public Users findUser(String uname, String pwd) {
return userDao.findUser(uname,pwd);
} /**
* 处理用户激活操作
* @param uid
*/
@Override
public void updateUserLock(int uid) {
userDao.updateUser(uid);
} /**
* 处理用户激活
* @param uname
* @param pwd
*/
@Override
public void updateLock(String uname,String pwd) {
userDao.updateUserlocked(uname,pwd);
}
}

控制层

com.bjsxt.controller.PageController(页面跳转)

package com.bjsxt.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; @Controller
public class PageController { /***
* 展示页面
* @return
*/
@RequestMapping("/{page}")
public String showPage(@PathVariable String page){
return page;
}
}

com.bjsxt.controller.UserController用户操作处理

package com.bjsxt.controller;

import com.bjsxt.pojo.Users;
import com.bjsxt.send.LoginSender;
import com.bjsxt.send.RegSender;
import com.bjsxt.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date; @Controller
public class UserController { @Autowired
private JavaMailSender mailSender; @Autowired
private UserService us; @Autowired
private RegSender regSender; @Autowired
private LoginSender loginSender; @RequestMapping("/save")
public String addUser(Users users){
us.addUser(users); //将Email-时间-URL格式的数据保存到队列中
String email = users.getEmail();
Date now =new Date();
SimpleDateFormat spdf=new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
String date = spdf.format(now);
String url="http://192.168.41.24:8081/locked/"+users.getUid();
regSender.sendMsg("邮箱:"+email+"\t时间:"+date+"\turl:"+url); /**
* 向qq邮箱发送信息
*/
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("1252639547@qq.com");//信息由谁发送
message.setTo(users.getEmail());//信息发送给谁
message.setSubject("主人主人!!你有新邮件啦~");//设置邮件的主题
message.setText(url);//设置邮件的内容
mailSender.send(message);
return "login"; } @RequestMapping("/loginuser")
public String login(String uname, String pwd, HttpServletRequest request){
Users user = us.findUser(uname, pwd);
if (user!=null){
//电话-时间-IP格式的数据保存到队列中
String phone = user.getPhone();
Date now =new Date();
SimpleDateFormat spdf=new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
String date = spdf.format(now);
String ip = request.getRemoteHost();
loginSender.sendMsg("电话:"+phone+"\t时间:"+date+"\tIP:"+ip);
return "success";
}else {
request.setAttribute("uname",uname);
request.setAttribute("pwd",pwd);
return "cuowu";
} } /**
* 处理用户激活
* @param uid
* @return
*/
@RequestMapping("/locked/{uid}")
public String bindLock(@PathVariable int uid){
us.updateUserLock(uid);
return "success1";
} /**
* 处理用户激活
* @param uname
* @param pwd
* @return
*/
@RequestMapping("/lock/{uname}/{pwd}")
public String Locked(@PathVariable String uname,@PathVariable String pwd){
us.updateLock(uname,pwd);
return "success1";
} }

前端的页面分步

注册界面

templates/reg.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8"/>
<title>注册</title>
</head>
<body>
<h1 style="align-content: center">用户注册</h1>
<form th:action="@{/save}" method="post" style="align-content: center">
<p>
用户名:<input type="text" name="uname">
</p>
<p>
密码:<input type="password" name="pwd">
</p>
<p>
确认密码:<input type="password">
</p>
<p>
邮箱:<input type="email" name="email">
</p>
<p>
电话号码:<input type="number" name="phone">
</p>
<p>
<input type="submit" value="注册">
</p>
</form>
</body>
</html>

登录界面

templates/login.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<form method="post" th:action="@{/loginuser}">
<p>
用户名:<input type="text" name="uname">
</p>
<p>
密码:<input type="password" name="pwd">
</p>
<p>
<input type="submit" value="登录">&nbsp;&nbsp;<a href="reg.html">戳我去注册</a>
</p>
</form>
</body>
</html>

当你注册成功后,但是没有激活直接登录,失败界面

templates/cuowu.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>主页面</title>
</head>
<body>
<h1>亲,你还未激活,请点击激活后登录</h1>
<table border="1">
<tr>
<th>用户名</th>
<th>密码</th>
<th>操作</th>
</tr>
<tr>
<th th:text="${uname}"></th>
<th th:text="${pwd}"></th>
<th><a th:href="@{/lock/}+${uname}+@{/}+${pwd}">激活</a></th>
</tr>
</table>
</body>
</html>

用户激活成功页面

templates/success1.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>激活页面</title>
</head>
<body>
<h1><a th:href="@{/login.html}">用户激活成功,戳我去登录</a></h1>
</body>
</html>

登录成功页面

templates/success.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>主页面</title>
</head>
<body>
<h1>登录成功</h1>
</body>
</html>

消息接受者  spring-boot-jpa-zcdl-consumer

pom文件

<?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.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bjsxt</groupId>
<artifactId>spring-boot-jpa-zcdl-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-jpa-zcdl-consumer</name>
<description>spring-boot-jpa-zcdl-consumer</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<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-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-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=8082
spring.rabbitmq.host=192.168.181.134
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=111111 #设置交换器的名称
mq.config.exchange=log.direct #设置短信队列名称
mq.config.queue.message=log.message #设置短信的路由键
mq.config.queue.message.routing.key=log.message.routing.key #设置邮件队列名称
mq.config.queue.email=log.email #设置邮件的路由键
mq.config.queue.email.routing.key=log.email.routing.key

接收消息

com.bjsxt.receiver.EmailReceiver

package com.bjsxt.receiver;

import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component; @Component
@RabbitListener(
bindings = @QueueBinding(
value =@Queue(value = "${mq.config.queue.email}",autoDelete = "true"),
exchange = @Exchange(value = "${mq.config.exchange}",type = ExchangeTypes.DIRECT),
key = "${mq.config.queue.email.routing.key}"
) )
public class EmailReceiver {
/**
* 接收消息的方法
* 采用消息队列监听机制
* @param msg
*/
@RabbitHandler
public void process(String msg){
System.out.println("邮件消息:"+msg);
}
}

com.bjsxt.receiver.MessageReceiver

package com.bjsxt.receiver;

import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component; @Component
@RabbitListener(
bindings = @QueueBinding(
value =@Queue(value = "${mq.config.queue.message}",autoDelete = "true"),
exchange = @Exchange(value = "${mq.config.exchange}",type = ExchangeTypes.DIRECT),
key = "${mq.config.queue.message.routing.key}"
) )
public class MessageReceiver {
/**
* 接收消息的方法
* 采用消息队列监听机制
* @param msg
*/
@RabbitHandler
public void process(String msg){
System.out.println("短信消息:"+msg);
}
}

Spring Boot 整合Spring Data以及rabbitmq,thymeleaf,向qq邮箱发送信息的更多相关文章

  1. Spring Boot 整合Spring Data JPA

    Spring Boot整合Spring Data JPA 1)加入依赖 <dependency> <groupId>org.springframework.boot</g ...

  2. Spring boot 整合spring Data JPA+Spring Security+Thymeleaf框架(上)

    近期上班太忙所以耽搁了给大家分享实战springboot 框架的使用. 以下是spring boot 整合多个框架的使用. 首先是准备工作要做好. 第一  导入框架所需的包,我们用的事maven 进行 ...

  3. Spring Boot整合Spring Security自定义登录实战

    本文主要介绍在Spring Boot中整合Spring Security,对于Spring Boot配置及使用不做过多介绍,还不了解的同学可以先学习下Spring Boot. 本demo所用Sprin ...

  4. Spring Boot整合Spring Security总结

    一.创建Spring Boot项目 引入Thymeleaf和Web模块以及Spring Security模块方便进行测试,先在pom文件中将 spring-boot-starter-security ...

  5. Spring Boot整合Spring Security

    Spring Boot对于该家族的框架支持良好,但是当中本人作为小白配置还是有一点点的小问题,这里分享一下.这个项目是使用之前发布的Spring Boot会员管理系统重新改装,将之前filter登录验 ...

  6. Spring Boot整合Spring Batch

    引言 Spring Batch是处理大量数据操作的一个框架,主要用来读取大量数据,然后进行一定的处理后输出指定的形式.比如我们可以将csv文件中的数据(数据量几百万甚至几千万都是没问题的)批处理插入保 ...

  7. Spring Boot整合Spring Session实战

    传统java web应用session都是由应用服务器(如tomcat)保存在内存中,这对应但节点应用来说没问题:但对于应用集群来说会造成各节点之间的session无法共享,一个节点挂掉后,其他节点接 ...

  8. Spring Boot 整合 Spring Security,用户登录慢

    场景 Spring Boot + Spring Security搭建一个Web项目. 临时用了inMemoryAuthentication. @EnableWebSecurity public cla ...

  9. spring boot整合spring Data JPA和freemarker

    1.spring Data JPA简介 是一个替代hibernate的一个作用于数据库的框架. 2.整合 1.导入依赖 <dependency> <groupId>org.sp ...

随机推荐

  1. 使用ASP.NET Core 3.x 构建 RESTful API - 3.1 资源命名

    之前讲了RESTful API的统一资源接口这个约束,里面提到了资源是通过URI来进行识别的,每个资源都有自己的URI.URI里还涉及到资源的名称,而针对资源的名称却没有一个标准来进行规范,但是业界还 ...

  2. 监听器以及在监听类里面获得bean的方法

    1实现HttpSessionListener和ServletContextListener,2个接口 2然后在contextInitialized初始化方法里面: ServletContext app ...

  3. 《计算机网络 自顶向下方法》 第6章 链路层和局域网 Part2

    待补充完善 Web 页面的请求历程 应用层     报文.主机 运输层     报文段. 网络层     数据报.路由器.IP 地址 链路层     以太网帧.交换机.MAC 地址 步骤 1)到 4) ...

  4. 超简单解决linux音乐播放器乱码问题

    问题 中文MP3的tag信息有些因为采用了GBK编码, 导致linux下的大多播放器(Rhythmbox, Audacious)无法正确识别而显示乱码. 如下图Audacious的乱码情况. 网上的常 ...

  5. 关于laravel框架Model返回的值为stdClass对象转换两种方法

    一般情况下laravel模型层查询出来的数据是stdClass对象,无法直接当做数组进行视图展示,所以需要转换为数组格式. Model中查到的数据为  $data  ,对它进行转化,转化为数组. 第一 ...

  6. 利用Xshell配置ssh免密码登录虚拟机,进行虚拟机与物理机的传输

    先说一下 Xshell如何无密连接虚拟机: ssh登录提供两种认证方式:口令(密码)认证方式和密钥认证方式.其中口令(密码)认证方式是我们最常用的一种,这里介绍密钥认证方式登录到linux的方法.使用 ...

  7. ZeroC Ice发送大数据

    继上文,我们使用ZeroC Ice传递大块数据时,通常有两种做法,一种是一次请求,另一种就是分多次请求(,这种做法在官方文档有例子).选哪一种根据需要而定. 当分多次请求来完成一大块数据,到底选择每次 ...

  8. vant-ui的van-uploader上传图片

    移动端上传图片是很常用的功能,这里使用vant-ui实现. 效果如图 上传图片的vue页面:Customer.vue html <div :class="postData.length ...

  9. 基于HTTP协议的WAF绕过

    一,畸形包绕过 1.先关闭burpsuite长度更新,为get请求,先使用bp的method转换为POST请求 2.get请求中空格使用%20代替,Connection改为keep-alive 二,分 ...

  10. 学会使用这些,你的Windows可能会焕然一新

    星选哥用Windows也已经好多年了,今天用室友的电脑才发现,桌面真可以影响一个人的心情,从而影响工作,学习,生活. 所以准备推荐一些好用且轻量的小工具,让你时时刻刻有个好心情. 室友的桌面(还有很多 ...