一、友链管理
和分类一样,友链除了基本的增删查改,还要防止友链地址重复。
详细分析可看oneStar的博客内容。
这里一次性展示接口的全部代码。
1.DAO持久层
在dao
包下创建FriendLinkDao
接口。
@Mapper
@Repository
public interface FriendLinkDao {
//查询友链管理列表
List<FriendLink> listFriendLink();
//新增友链
int saveFriendLink(FriendLink friendLink);
//根据网址查询友链
FriendLink getFriendLinkByBlogaddress(String blogaddress);//防止重复
//根据id查询友链
FriendLink getFriendLink(Long id); //编辑时可传入对应分类
//编辑修改友链
int updateFriendLink(FriendLink friendLink);
//删除友链
void deleteFriendLink(Long id);
}
2.友链管理mapper
在mapper
文件夹下创建FriendLinkDao.xml
文件
<?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.hxj.dao.FriendLinkDao">
<!--已经 进行驼峰 转换配置了,不用配置resultMap-->
<!--查询友链管理列表-->
<select id="listFriendLink" resultType="FriendLink">
select *
from t_friend ;
</select>
<!--根据网址查询友链-->
<select id="getFriendLinkByBlogaddress" resultType="FriendLink">
select *
from t_friend where blogaddress = #{blogaddress};
</select>
<!--新增友链-->
<insert id="saveFriendLink" parameterType="FriendLink">
insert into t_friend (blogaddress, blogname, create_time, pictureaddress)
values (#{blogaddress},#{blogname},#{createTime},#{pictureaddress});
</insert>
<!--根据id查询友链-->
<select id="getFriendLink" resultType="FriendLink">
select *
from t_friend
where id = #{id};
</select>
<!--修改友链-->
<update id="updateFriendLink" parameterType="FriendLink">
update t_friend
set blogaddress = #{blogaddress},blogname=#{blogname},pictureaddress=#{pictureaddress}
where id=#{id};
</update>
<delete id="deleteFriendLink">
delete
from t_friend
where id=#{id};
</delete>
</mapper>
3.友链管理Service业务层
在service
包创建用户业务层接口FriendLinkService
。
public interface FriendLinkService {
//查询友链管理列表
List<FriendLink> listFriendLink();
//新增友链
int saveFriendLink(FriendLink friendLink);
//根据网址查询友链
FriendLink getFriendLinkByBlogaddress(String blogaddress);
//根据id查询友链
FriendLink getFriendLink(Long id);
//编辑修改友链
int updateFriendLink(FriendLink friendLink);
//删除友链
void deleteFriendLink(Long id);
}
接口实现类impl
在impl
子包,在其中创建用户业务层接口实现类FriendLinkServiceImpl
。
@Service
public class FriendLinkServiceImpl implements FriendLinkService {
@Autowired
private FriendLinkDao FriendLinkDao;
@Override
public List<FriendLink> listFriendLink() {
return FriendLinkDao.listFriendLink();
}
@Override
public int saveFriendLink(FriendLink friendLink) {
return FriendLinkDao.saveFriendLink(friendLink);
}
@Override
public FriendLink getFriendLinkByBlogaddress(String blogaddress) {
return FriendLinkDao.getFriendLinkByBlogaddress(blogaddress);
}
@Override
public FriendLink getFriendLink(Long id) {
return FriendLinkDao.getFriendLink(id);
}
@Override
public int updateFriendLink(FriendLink friendLink) {
return FriendLinkDao.updateFriendLink(friendLink);
}
@Override
public void deleteFriendLink(Long id) {
FriendLinkDao.deleteFriendLink(id);
}
}
4.友链管理Controller控制器
同理的页面跳转也使用了局部刷新,虽然冗余了点。
定义要更新区域成一个fragment:
分页前端改动:
<input type="hidden" name="page" >
...
...
...
<div class="two wide column" align="center">
<a class="item" style="cursor: pointer" onclick="page(this)" th:attr="data-page=1" th:unless="${pageInfo.isFirstPage}">首页</a>
</div>
<div class="two wide column" align="center">
<a class="item" style="cursor: pointer" onclick="page(this)" th:attr="data-page=${pageInfo.hasPreviousPage}?${pageInfo.prePage}:1" th:unless="${pageInfo.isFirstPage}">上一页</a>
</div>
<div class="eight wide column" align="center">
<p>第 <span th:text="${pageInfo.pageNum}"></span> 页,共 <span th:text="${pageInfo.pages}"></span> 页,有 <span th:text="${pageInfo.total}"></span> 篇文章</p>
</div>
<div class="two wide column " align="center">
<a class="item" style="cursor: pointer" onclick="page(this)" th:attr="data-page=${pageInfo.hasNextPage}?${pageInfo.nextPage}:${pageInfo.pages}" th:unless="${pageInfo.isLastPage}">下一页</a>
</div>
<div class="two wide column " align="center">
<a class="item" style="cursor: pointer" onclick="page(this)" th:attr="data-page=${pageInfo.pages}" th:unless="${pageInfo.isLastPage}">尾页</a>
</div>
JS部分新增:
function page(obj) {
$("[name='page']").val($(obj).data("page"));
loaddata();
}
function loaddata() {
$("#types-container").load(/*[[@{/admin/refreshType}]]*/
"/admin/refreshType",{
pageNum : $("[name='page']").val()
});
}
在controller.admin
包下,创建FriendLinkController
,代码如下:
和oneStar博客不同的是,在修改友链时,地址的查重判断不判断本身的(只判断除自身外的其他友链是否重复即可)。
@Controller
@RequestMapping("/admin")
public class FriendLinkController {
@Autowired
private FriendLinkService FriendLinkService;
//友链管理界面
@GetMapping("/friendlinks")
public String list(Model model, @RequestParam(defaultValue = "1", value = "pageNum") Integer pageNum) {
String orderBy = "create_time desc";
PageHelper.startPage(pageNum, 5, orderBy);
List<FriendLink> friendLinks = FriendLinkService.listFriendLink();
PageInfo<FriendLink> pageInfo = new PageInfo<>(friendLinks);
model.addAttribute("pageInfo", pageInfo);
return "admin/friendlinks";
}
//有点冗余,不想优化, 有人看到可以自行优化
@PostMapping("/refreshFriend")
public String refreshFriend(Model model, @RequestParam(defaultValue = "1", value = "pageNum") Integer pageNum){
String orderBy = "create_time desc";
PageHelper.startPage(pageNum, 5, orderBy);
List<FriendLink> friendLinks = FriendLinkService.listFriendLink();
PageInfo<FriendLink> pageInfo = new PageInfo<>(friendLinks);
model.addAttribute("pageInfo", pageInfo);
return "admin/friendlinks :: friendlink-list";
}
//跳转到 新增页面
@GetMapping("friendlinks/input")
public String input(Model model) {
model.addAttribute("friendLink", new FriendLink());
return "admin/friendlinks-input";
}
//提交新增
@PostMapping("/friendlinks")
public String post(@Valid FriendLink friendLink, BindingResult result, RedirectAttributes attributes) {
if(result.hasErrors()){
//校验出来,发现问题,把message传前端
System.out.println(result);
return "admin/friendlinks-input";
}
FriendLink friendLink1 = FriendLinkService.getFriendLinkByBlogaddress(friendLink.getBlogaddress());
if (friendLink1 != null) {
attributes.addFlashAttribute("message", "不能添加相同地址的友链");
return "redirect:/admin/friendlinks/input";
}
friendLink.setCreateTime(new Date());
int i = FriendLinkService.saveFriendLink(friendLink);
if (i == 0) {
attributes.addFlashAttribute("message", "添加失败");
} else {
attributes.addFlashAttribute("message", "添加成功");
}
return "redirect:/admin/friendlinks";
}
//编辑 友链
@GetMapping("/friendlinks/{id}/input")
public String editInput(@PathVariable("id") Long id, Model model) {
//根据id 传对应的 friendlink
FriendLink friendLink = FriendLinkService.getFriendLink(id);
model.addAttribute("friendLink", friendLink);
return "admin/friendlinks-input";
}
//提交修改友链
@PostMapping("/friendlinks/{id}")
public String editPost(@Valid FriendLink friendLink, BindingResult result, RedirectAttributes attributes) {
if(result.hasErrors()){
//校验出来,发现问题,把message传前端
System.out.println(result);
return "admin/friendlinks-input";
}
//友链的地址不能和 除自己之外的 重复(特判)
FriendLink friendLink1 = FriendLinkService.getFriendLinkByBlogaddress(friendLink.getBlogaddress());
if (friendLink1 != null) {
if (friendLink1.getId().equals(friendLink.getId())) {
//同一个就不用特判了
} else {
//如果是和不同 友链冲突
attributes.addFlashAttribute("message", "不能添加重复的友链地址");
return "redirect:/admin/friendlinks/{id}/input"; //回到新增(有id还是进 编辑)页面
}
}
int i = FriendLinkService.updateFriendLink(friendLink);
if (i == 0) {
attributes.addFlashAttribute("message", "编辑失败");
} else {
attributes.addFlashAttribute("message", "编辑成功");
}
return "redirect:/admin/friendlinks"; //回到展示列表
}
//删除 友链
@GetMapping("/friendlinks/{id}/delete")
public String delete(@PathVariable("id") Long id, RedirectAttributes attributes) {
FriendLinkService.deleteFriendLink(id);
attributes.addFlashAttribute("message", "删除成功");
return "redirect:/admin/friendlinks";
}
}
二、相册管理
同理,除了基本的增删查改,但不需要做图片链接的查重,有该需求者自行修改。
1.DAO持久层
在dao
包下创建PictureDao
接口,代码如下:
@Mapper
@Repository
public interface PictureDao {
//图片列表
List<Picture> listPicture();
//添加图片
int savePicture(Picture picture);
//根据id查询图片
Picture getPicture(Long id);
//编辑修改相册
int updatePicture(Picture picture);
//删除照片
void deletePicture(Long id);
}
2.友链管理mapper
在mapper
文件夹下创建PictureDao.xml
文件
<?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.hxj.dao.PictureDao">
<!--图片列表-->
<select id="listPicture" resultType="Picture">
select *
from t_picture ;
</select>
<!--添加图片-->
<insert id="savePicture" parameterType="Picture">
insert into t_picture (pictureaddress, picturedescription, picturename, picturetime)
values (#{pictureaddress},#{picturedescription},#{picturename},#{picturetime});
</insert>
<!--根据id查询图片-->
<select id="getPicture" resultType="Picture">
select *
from t_picture where id = #{id};
</select>
<!--编辑修改相册-->
<update id="updatePicture" parameterType="Picture">
update t_picture
set pictureaddress = #{pictureaddress},picturename=#{picturename},picturedescription=#{picturedescription},picturetime=#{picturetime}
where id=#{id};
</update>
<!--删除照片-->
<delete id="deletePicture">
delete
from t_picture
where id=#{id};
</delete>
</mapper>
3.图片管理Service业务层
在service
包创建用户业务层接口PictureService
。
public interface PictureService {
//图片列表
List<Picture> listPicture();
//添加图片
int savePicture(Picture picture);
//根据id查询图片
Picture getPicture(Long id);
//编辑修改相册
int updatePicture(Picture picture);
//删除照片
void deletePicture(Long id);
}
接口实现类impl
在impl
子包,在其中创建用户业务层接口实现类PictureServiceImpl
。
@Service
public class PictureServiceImpl implements PictureService {
@Autowired
private PictureDao pictureDao;
@Override
public List<Picture> listPicture() {
return pictureDao.listPicture();
}
@Override
public int savePicture(Picture picture) {
return pictureDao.savePicture(picture);
}
@Override
public Picture getPicture(Long id) {
return pictureDao.getPicture(id);
}
@Override
public int updatePicture(Picture picture) {
return pictureDao.updatePicture(picture);
}
@Override
public void deletePicture(Long id) {
pictureDao.deletePicture(id);
}
}
4.图片管理Controller控制器
同理的页面跳转也使用了局部刷新,虽然冗余了点。
定义要更新区域成一个fragment:
分页前端改动:
<input type="hidden" name="page" >
...
...
...
<div class="two wide column" align="center">
<a class="item" style="cursor: pointer" onclick="page(this)" th:attr="data-page=1" th:unless="${pageInfo.isFirstPage}">首页</a>
</div>
<div class="two wide column" align="center">
<!--<a class="item" th:href="@{/admin/blogs(pageNum=${pageInfo.hasPreviousPage}?${pageInfo.prePage}:1)}" th:unless="${pageInfo.isFirstPage}">上一页</a>-->
<a class="item" style="cursor: pointer" onclick="page(this)" th:attr="data-page=${pageInfo.hasPreviousPage}?${pageInfo.prePage}:1" th:unless="${pageInfo.isFirstPage}">上一页</a>
</div>
<div class="eight wide column" align="center">
<p>第 <span th:text="${pageInfo.pageNum}"></span> 页,共 <span th:text="${pageInfo.pages}"></span> 页,有 <span th:text="${pageInfo.total}"></span> 篇文章</p>
</div>
<div class="two wide column " align="center">
<!--<a class="item" th:href="@{/admin/blogs(pageNum=${pageInfo.hasNextPage}?${pageInfo.nextPage}:${pageInfo.pages})}" th:unless="${pageInfo.isLastPage}">下一页</a>-->
<a class="item" style="cursor: pointer" onclick="page(this)" th:attr="data-page=${pageInfo.hasNextPage}?${pageInfo.nextPage}:${pageInfo.pages}" th:unless="${pageInfo.isLastPage}">下一页</a>
</div>
<div class="two wide column " align="center">
<a class="item" style="cursor: pointer" onclick="page(this)" th:attr="data-page=${pageInfo.pages}" th:unless="${pageInfo.isLastPage}">尾页</a>
</div>
</div>
<div align="center">
<a href="#" th:href="@{/admin/pictures/input}">
<button type="button" class="ui teal button m-mobile-wide m-margin-top"><i class="pencil icon"></i>新增</button>
</a>
</div>
JS部分新增:
function page(obj) {
$("[name='page']").val($(obj).data("page"));
loaddata();
}
function loaddata() {
$("#picture-container").load(/*[[@{/admin/refreshPicture}]]*/
"/admin/refreshPicture",{
pageNum : $("[name='page']").val()
});
}
在controller.admin
包下,创建PictureController
,代码如下:
@Controller
@RequestMapping("/admin")
public class PictureController {
@Autowired
private PictureService pictureService;
//图片 管理列表(分页)
@GetMapping("/pictures")
public String list(Model model,@RequestParam(defaultValue = "1",value = "pageNum") Integer pageNum){
//已经规定按照数据库id降序
String orderBy ="id desc";
PageHelper.startPage(pageNum,2,orderBy);
List<Picture> pictures = pictureService.listPicture();
PageInfo<Picture> pageInfo = new PageInfo<>(pictures); //封装查询信息
model.addAttribute("pageInfo", pageInfo);
return "admin/pictures";
}
@PostMapping("/refreshPicture")
public String refreshPicture(Model model,@RequestParam(defaultValue = "1",value = "pageNum") Integer pageNum){
//已经规定按照数据库id降序
String orderBy ="id desc";
PageHelper.startPage(pageNum,2,orderBy);
List<Picture> pictures = pictureService.listPicture();
PageInfo<Picture> pageInfo = new PageInfo<>(pictures); //封装查询信息
model.addAttribute("pageInfo", pageInfo);
return "admin/pictures :: pictureList";
}
//进入新增页面
@GetMapping("/pictures/input")
public String input(Model model){
model.addAttribute("picture", new Picture());
return "admin/pictures-input";
}
//提交新增(先不做后端校验)
@PostMapping("/pictures")
public String post(@Valid Picture picture, BindingResult result, RedirectAttributes attributes){
if(result.hasErrors()){
return "admin/pictures-input";
}
int i = pictureService.savePicture(picture);
if(i==0){
attributes.addFlashAttribute("message","新增失败");
}else {
attributes.addFlashAttribute("message","新增成功");
}
return "redirect:/admin/pictures"; //返回列表
}
//进入修改界面
@GetMapping("/pictures/{id}/input")
public String editInput(@PathVariable("id")Long id,Model model){
Picture picture = pictureService.getPicture(id);
model.addAttribute("picture",picture);
return "/admin/pictures-input";
}
//提交修改
@PostMapping("/pictures/{id}")
public String editPost(@Valid Picture picture, BindingResult result,RedirectAttributes attributes){
if(result.hasErrors()){
return "admin/pictures-input";
}
int i = pictureService.updatePicture(picture);
if(i==0){
attributes.addFlashAttribute("message","编辑失败");
}else{
attributes.addFlashAttribute("message","编辑成功");
}
return "redirect:/admin/pictures";
}
@GetMapping("/pictures/{id}/delete")
public String delete(@PathVariable("id")Long id,RedirectAttributes attributes){
pictureService.deletePicture(id);
attributes.addFlashAttribute("message","删除成功");
return "redirect:/admin/pictures";
}
}
小结
至此,后台功能的实现已经全部完成
四个管理模块都能实现基本的【增删改查】功能,都是能局部刷新实现分页。
目前只有博客模块用到了搜索,其余模块没有,若想实现其余模块的搜索功能,可以仿照博客模块。改动前端和controller接口即可。
目前图像相关的都使用了项目内部的资源(若有图床也可以更换为远程资源)
效果示例图:
下一阶段将开始进行前台功能的实现。