VBlog项目代码理解之后端
文章目录
VBlog项目代码理解之后端
资源
项目地址
前后端交互代码理解
前端代码理解
推荐:整个项目几乎是只用到了SpringBoot、Vue、Mybatis、ElementUI,没有用到Redis、RabbitMQ等内容,很适合刚学完SpringBoot和Vue的同学练手,感谢作者!帮作者打个广告吧~
PS:这是本人第一个学习的项目,难免会有错误的地方,哪里有问题烦请指正,感谢!
因为主要学的后端,之前也练过图书管理系统,所以没什么好详细记录的,就是有些Mybatis
操作还不熟悉。
Bean
很多bean类,但只有User
类实现了UserDetails
(UserDetails
和UserDetailsService
在下面的Spring Security
有介绍),其他的类都通过id等方式和User绑定。
要特别注意的方法就是getAuthorities()
还用@JsonIgnore
注释了一些重载方法,注意中间isEnabled()
没有用这个注释
@Override
@JsonIgnore
public boolean isAccountNonExpired() {
return true;
}
@Override
@JsonIgnore
public boolean isAccountNonLocked() {
return true;
}
@Override
@JsonIgnore
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@Override
@JsonIgnore
public List<GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
}
return authorities;
}
Mapper
就是一些基础方法的组合
迷惑:
-
分页:
<!--状态与权限的搜索,为啥还限制了分页?--> <select id="getArticleByStateByAdmin" resultType="org.sang.bean.Article"> SELECT a.id,a.`title`,a.`editTime`,a.`pageView`,a.`state`,u.`nickname`,c.`cateName`,a.uid FROM article a,user u,category c WHERE a.`cid`=c.`id` AND a.`uid`=u.`id` and a.state=1 <if test="keywords!=null"> AND title LIKE concat('%',#{keywords},'%') </if> ORDER BY a.editTime DESC limit #{start},#{count}; </select> <select id="getArticleCountByState" resultType="int"> SELECT count(*) FROM article <where> <if test="state!=-1"> AND state=#{state} </if> <if test="uid!=null"> AND uid=#{uid} </if> <if test="keywords!=null"> AND title LIKE concat('%',#{keywords},'%') </if> </where> </select>
-
奇怪的LEFT、JOIN、ON
<!--啊!LEFT JOIN ON是啥--> <select id="getArticleById" parameterType="Long" resultMap="BaseResultMap"> SELECT a.*,t.`tagName`,t.`id` AS tid,u.`nickname`,c.`cateName` FROM article a LEFT JOIN article_tags ats ON a.`id`=ats.`aid` LEFT JOIN tags t ON ats.`tid`=t.`id` LEFT JOIN user u ON a.`uid`=u.`id` LEFT JOIN category c ON a.`cid`=c.`id` WHERE a.id=#{aid} </select> <resultMap id="BaseResultMap" type="org.sang.bean.Article"> <id column="id" property="id"/> <result column="title" property="title"/> <result column="cid" property="cid"/> <result column="uid" property="uid"/> <result column="publishDate" property="publishDate"/> <result column="editTime" property="editTime"/> <result column="state" property="state"/> <result column="pageView" property="pageView"/> <result column="mdContent" property="mdContent"/> <result column="htmlContent" property="htmlContent"/> <result column="summary" property="summary"/> <result column="nickname" property="nickname"/> <result column="cateName" property="cateName"/> <collection property="tags" ofType="org.sang.bean.Tags" column="tagName"> <id property="id" column="tid"/> <result property="tagName" column="tagName"/> </collection> </resultMap>
学习操作:
-
动态sql:
<!--根据状态看某种全部文章或者模糊搜索--> <!--用动态SQL实现两种功能,厉害--> <select id="getArticleByState" resultType="org.sang.bean.Article"> SELECT a.id,a.`title`,a.`editTime`,a.`pageView`,a.`state`,u.`nickname`,c.`cateName`,a.uid FROM article a,user u,category c WHERE a.`cid`=c.`id` AND a.`uid`=u.`id` <if test="state!=-2"> and a.uid=#{uid} </if> <if test="state!=-1 and state!=-2"> and a.state=#{state} </if> <if test="state==-2"> and a.state=1 </if> <if test="keywords!=null"> AND title LIKE concat('%',#{keywords},'%') </if> ORDER BY a.editTime DESC limit #{start},#{count}; </select>
-
foreach:
<!--批量更新,应是对应着批量删除操作,把文章放入回收站--> <!--学学foreach--> <update id="updateArticleState"> UPDATE article SET state=#{state} WHERE id IN <foreach collection="aids" item="aid" separator="," open="(" close=")"> #{aid} </foreach> </update>
-
有自增主键,用null填上:
<insert id="addRoles"> INSERT INTO roles_user VALUES <foreach collection="roles" item="role" separator=","> (null,#{role},#{uid}) </foreach> </insert>
Service
UserService:
还是只有UserService
实现了UserDetailsService
方法。
重写的loadUserByUsername
方法。
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userMapper.loadUserByUsername(s);
if (user == null) {
//避免返回null,这里返回一个不含有任何值的User对象,在后期的密码比对过程中一样会验证失败
return new User();
}
// 查询用户的角色信息,并返回存入user中
// 如果user为null这里就会报错
List<Role> roles = rolesMapper.getRolesByUid(user.getId());
user.setRoles(roles);
return user;
}
public int reg(User user) {
User loadUserByUsername = userMapper.loadUserByUsername(user.getUsername());
// 看看用这个名字能不能读出数据,能就代表名字重复了
if (loadUserB yUsername != null) {
// 重复
return 1;
}
//插入用户,插入之前先对密码进行加密
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setEnabled(true);//用户可用
long result = userMapper.reg(user);
//配置用户的角色,默认都是普通用户
String[] roles = new String[]{"2"};
int i = rolesMapper.addRoles(roles, user.getId());
boolean b = i == roles.length && result == 1;
if (b) {
// 成功
return 0;
} else {
// 失败
return 2;
}
}
其他的部分平平无奇
CategoryService:
批量删除的操作比较有意思,传进去的就是一个String数组
public boolean deleteCategoryByIds(String ids) {
String[] split = ids.split(",");
int result = categoryMapper.deleteCategoryByIds(split);
return result == split.length;
}
int deleteCategoryByIds(@Param("ids") String[] ids);
<delete id="deleteCategoryByIds">
DELETE FROM category WHERE id IN
<foreach collection="ids" separator="," open="(" close=")" item="id">
#{id}
</foreach>
</delete>
DataStatisticsComponent:
使用了一个定时执行注解:
好像是倒着来,每天0 : 01会执行一次
这个注解要在XXXApplication
文件中开启注解支持@EnableScheduling//开启定时任务支持
//每天执行一次,统计PV
@Scheduled(cron = "1 0 0 * * ?")
public void pvStatisticsPerDay() {
articleService.pvStatisticsPerDay();
}
ArticleService:
比较复杂的就是文章和对应标签的
public int addNewArticle(Article article) {
//处理文章摘要, 如果没写的话就截取前50个字符
if (article.getSummary() == null || "".equals(article.getSummary())) {
//直接截取
String stripHtml = stripHtml(article.getHtmlContent());
article.setSummary(stripHtml.substring(0, stripHtml.length() > 50 ? 50 : stripHtml.length()));
}
// id=-1就是刚添加的,有id就是更新
if (article.getId() == -1) {
//添加操作
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
if (article.getState() == 1) {
//设置发表日期
article.setPublishDate(timestamp);
}
article.setEditTime(timestamp);
// 设置当前用户,同时添加到数据库
article.setUid(Util.getCurrentUser().getId());
int i = articleMapper.addNewArticle(article);
// 打标签,也是加到数据库中
// 因为文章和tag是两个类,通过id绑定,所以不能一步走
String[] dynamicTags = article.getDynamicTags();
if (dynamicTags != null && dynamicTags.length > 0) {
int tags = addTagsToArticle(dynamicTags, article.getId());
if (tags == -1) {
return tags;
}
}
return i;
} else {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
if (article.getState() == 1) {
//设置发表日期
article.setPublishDate(timestamp);
}
//更新
article.setEditTime(new Timestamp(System.currentTimeMillis()));
int i = articleMapper.updateArticle(article);
//修改标签
String[] dynamicTags = article.getDynamicTags();
if (dynamicTags != null && dynamicTags.length > 0) {
int tags = addTagsToArticle(dynamicTags, article.getId());
if (tags == -1) {
return tags;
}
}
return i;
}
}
private int addTagsToArticle(String[] dynamicTags, Long aid) {
//1.删除该文章目前所有的标签
tagsMapper.deleteTagsByAid(aid);
//2.将上传上来的标签全部存入数据库
tagsMapper.saveTags(dynamicTags);
//3.查询这些标签的id
List<Long> tIds = tagsMapper.getTagsIdByTagName(dynamicTags);
//4.重新给文章设置标签
int i = tagsMapper.saveTags2ArticleTags(tIds, aid);
return i == dynamicTags.length ? i : -1;
}
Config:登录Spring Security配置
看Spring Security的笔记就行。
笔记地址
Controller
注意权限,如果有多个权限,那不同的权限处理放到不同的文件夹较好。而且在对应的控制类上加上权限的前缀,如/admin
,/user
,这样也方便后面的config
中的权限管理。
当使用SpringBoot和Vue做前后端分离的项目的时候,controller
是不做视图跳转的,并不能控制到视图,跳转都被Vue
的router
做了,所以一般都在controller上加了@RestController
注解。
Resources:配置文件与前端资源
将Vue
的内容做npm run build
,就会生成一个dist
文件啊加,将其中的文件夹static
和文件index.html
拷贝到后端项目的resources/static/
,再在application.properties
中设置端口号server.port=xxxx
,运行SpringBoot就行了,输入http://localhost:xxxx/index.html
即可。
上一篇: 烧麦是蒸熟以后再放冰箱里吗
推荐阅读
-
spring学习之创建项目 Hello Spring实例代码
-
简单理解Spring之IOC和AOP及代码示例
-
Android项目实战之Glide 高斯模糊效果的实例代码
-
从零开始搭建前后端分离的NetCore2.2(EF Core CodeFirst+Autofac)+Vue的项目框架之七使用JWT生成Token(个人见解)
-
从零开始搭建前后端分离的NetCore2.2(EF Core CodeFirst+Autofac)+Vue的项目框架之十一Swagger使用一
-
spring学习之创建项目 Hello Spring实例代码
-
从零开始搭建前后端分离的NetCore2.2(EF Core CodeFirst+Autofac)+Vue的项目框架之十数据库基础方法的封装
-
个人项目开源之c++基于epoll实现高并发游戏盒子(服务端+客户端)源代码
-
从零开始搭建前后端分离的NetCore2.2(EF Core CodeFirst+Autofac)+Vue的项目框架之九如何进行用户权限控制
-
.NET Core实战项目之CMS 第十一章 开发篇-数据库生成及实体代码生成器开发