【个人实习日志】Springboot新闻管理系统(一)
Springboot实现自动生成数据库表、登录注销以及分类展示
Springboot项目创建
一、自动生成数据库表
Springboot 之 Hibernate自动建表(Mysql)
先引入Maven依赖包,起作用的是如下两个:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
创建配置文件application.yml
server:
port: 8082
spring:
datasource:
url: jdbc:mysql://localhost:3306/tnews?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
//自动创建数据库表
jpa:
hibernate:
ddl-auto: update
show-sql: true//在控制台显示sql语句
本次项目po包中主要有五个实体类:
1、 在主建Id上需要加注释:@Id和@GeneratedValue(strategy = GenerationType.AUTO)才会自动增长
2、 在需要重新设置表字段名的属性上加注释@Column(name = “字段名”)即可。
3、 在类名上添加注释:@Entity和@Table(name = “t_user”),t_user是表名
Comment.java
package com.wzx.po;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Entity
@Table(name = "t_comment")
public class Comment {
@Id
@GeneratedValue
private Long id;
private String nickname;
private String email;
private String content;
private String avatar;
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;
@ManyToOne
private News news;
@OneToMany(mappedBy = "parentComment")
private List<Comment> replyComments = new ArrayList<>();
@ManyToOne
private Comment parentComment;
private boolean adminComment;
public Comment() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public List<Comment> getReplyComments() {
return replyComments;
}
public void setReplyComments(List<Comment> replyComments) {
this.replyComments = replyComments;
}
public Comment getParentComment() {
return parentComment;
}
public void setParentComment(Comment parentComment) {
this.parentComment = parentComment;
}
public boolean isAdminComment() {
return adminComment;
}
public void setAdminComment(boolean adminComment) {
this.adminComment = adminComment;
}
public News getNews() {
return news;
}
public void setNews(News news) {
this.news = news;
}
@Override
public String toString() {
return "Comment{" +
"id=" + id +
", nickname='" + nickname + '\'' +
", email='" + email + '\'' +
", content='" + content + '\'' +
", avatar='" + avatar + '\'' +
", createTime=" + createTime +
", news=" + news +
", replyComments=" + replyComments +
", parentComment=" + parentComment +
", adminComment=" + adminComment +
'}';
}
}
News.java
package com.wzx.po;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Entity
@Table(name = "t_News")
public class News {
@Id
@GeneratedValue
private Long id;
private String title;
@Basic(fetch = FetchType.LAZY)
@Lob
private String content;
private String firstPicture;
private String flag;
private Integer views;
private boolean appreciation;
private boolean shareStatement;
private boolean commentabled;
private boolean published;
private boolean recommend;
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;
@Temporal(TemporalType.TIMESTAMP)
private Date updateTime;
@ManyToOne
private Type type;
@ManyToMany(cascade = {CascadeType.PERSIST})
private List<Tag> tags = new ArrayList<>();
@ManyToOne
private User user;
@OneToMany(mappedBy = "news")
private List<Comment> comments = new ArrayList<>();
@Transient
private String tagIds;
private String description;
public News() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getFirstPicture() {
return firstPicture;
}
public void setFirstPicture(String firstPicture) {
this.firstPicture = firstPicture;
}
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
public Integer getViews() {
return views;
}
public void setViews(Integer views) {
this.views = views;
}
public boolean isAppreciation() {
return appreciation;
}
public void setAppreciation(boolean appreciation) {
this.appreciation = appreciation;
}
public boolean isShareStatement() {
return shareStatement;
}
public void setShareStatement(boolean shareStatement) {
this.shareStatement = shareStatement;
}
public boolean isCommentabled() {
return commentabled;
}
public void setCommentabled(boolean commentabled) {
this.commentabled = commentabled;
}
public boolean isPublished() {
return published;
}
public void setPublished(boolean published) {
this.published = published;
}
public boolean isRecommend() {
return recommend;
}
public void setRecommend(boolean recommend) {
this.recommend = recommend;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public List<Tag> getTags() {
return tags;
}
public void setTags(List<Tag> tags) {
this.tags = tags;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
public String getTagIds() {
return tagIds;
}
public void setTagIds(String tagIds) {
this.tagIds = tagIds;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public void init() {
this.tagIds = tagsToIds(this.getTags());
}
//1,2,3
private String tagsToIds(List<Tag> tags) {
if (!tags.isEmpty()) {
StringBuffer ids = new StringBuffer();
boolean flag = false;
for (Tag tag : tags) {
if (flag) {
ids.append(",");
} else {
flag = true;
}
ids.append(tag.getId());
}
return ids.toString();
} else {
return tagIds;
}
}
@Override
public String toString() {
return "News{" +
"id=" + id +
", title='" + title + '\'' +
", content='" + content + '\'' +
", firstPicture='" + firstPicture + '\'' +
", flag='" + flag + '\'' +
", views=" + views +
", appreciation=" + appreciation +
", shareStatement=" + shareStatement +
", commentabled=" + commentabled +
", published=" + published +
", recommend=" + recommend +
", createTime=" + createTime +
", updateTime=" + updateTime +
", type=" + type +
", tags=" + tags +
", user=" + user +
", comments=" + comments +
", tagIds='" + tagIds + '\'' +
", description='" + description + '\'' +
'}';
}
public void initTags(Long id) {
//3,4,5
List<Tag> tags = this.getTags();
StringBuffer ids=new StringBuffer();
if(!tags.isEmpty()){
Boolean flag=false;
for(Tag t:tags){
if(flag){
ids.append(t.getId());
flag=true;
}else {
ids.append(",");
ids.append(t.getId());
}
}
this.setTagIds(ids.toString());
}
}
}
Tag.java
package com.wzx.po;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "t_tag")
public class Tag {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany(mappedBy = "tags")
private List<News> newsList = new ArrayList<>();
public Tag() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<News> getNewsList() {
return newsList;
}
public void setNewsList(List<News> newsList) {
this.newsList = newsList;
}
@Override
public String toString() {
return "Tag{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Type.java
package com.wzx.po;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "t_type")
public class Type {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "type")
private List<News> newsList = new ArrayList<>();
public Type() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<News> getNewsList() {
return newsList;
}
public void setNewsList(List<News> newsList) {
this.newsList = newsList;
}
@Override
public String toString() {
return "Type{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
User.java
package com.wzx.po;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Entity
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue
private Long id;
private String nickname;
private String username;
private String password;
private String email;
private String avatar;
private Integer type;
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;
@Temporal(TemporalType.TIMESTAMP)
private Date updateTime;
@OneToMany(mappedBy = "user")
private List<News> newsList = new ArrayList<>();
public User() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public List<News> getNewsList() {
return newsList;
}
public void setNewsList(List<News> newsList) {
this.newsList = newsList;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", nickname='" + nickname + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
", avatar='" + avatar + '\'' +
", type=" + type +
", createTime=" + createTime +
", updateTime=" + updateTime +
'}';
}
}
启动项目后在tnews数据库中将出现数据表,且存在相应的表字段。
Springboot中先在实体类中建立与存储过程的联系,dao层调用存储过程,控制层调用dao层方法,dao层继承JpaRepository类实现简单的对数据库的操作。
二、登录注销功能
Springboot项目与SSM项目类似,只不过Springboot中的一些sql操作不用自己实现
(一)UserDao.java
package com.wzx.dao;
import com.wzx.po.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserDao extends JpaRepository<User,Long> {
User findByUsernameAndPassword(String username, String password);
}
(二)UserService.java
package com.wzx.service;
import com.wzx.po.User;
import org.springframework.stereotype.Service;
public interface UserService {
User CheckUser(String username, String password);
}
UserServiceImpl.java
package com.wzx.service.impl;
import com.wzx.dao.UserDao;
import com.wzx.po.User;
import com.wzx.service.UserService;
import com.wzx.util.MD5Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User CheckUser(String username, String password) {
return userDao.findByUsernameAndPassword(username, MD5Util.code(password));
}
}
(三)LoginController.java
package com.wzx.controller;
import com.wzx.po.User;
import com.wzx.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("admin")
public class LoginController {
@Autowired
private UserService userService;
@GetMapping
public String toLogin(){
return "admin/login";
}
@PostMapping("login")
public String login(String username, String password, HttpSession session, RedirectAttributes redirectAttributes){
User user=userService.CheckUser(username,password);
if(user!=null){
session.setAttribute("user",user);
return "admin/index";
}else {
redirectAttributes.addFlashAttribute("message","用户名和密码错误1");
return "redirect:/admin";
}
}
@GetMapping("logout")
public String logout(HttpSession session){
session.removeAttribute("user");
return "admin/login";
}
}
(四)login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head th:replace="admin/_fragments :: head(~{::title})">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>新闻管理登录</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.css">
<link rel="stylesheet" href="../../static/css/me.css">
</head>
<body>
<br>
<br>
<br>
<div class="m-container-small m-padded-tb-massive" style="max-width: 30em !important;">
<div class="ur container">
<div class="ui middle aligned center aligned grid">
<div class="column">
<h2 class="ui teal image header">
<div class="content">
管理后台登录
</div>
</h2>
<form class="ui large form" method="post" action="#" th:action="@{/admin/login}" >
<div class="ui segment">
<div class="field">
<div class="ui left icon input">
<i class="user icon"></i>
<input type="text" name="username" placeholder="用户名">
</div>
</div>
<div class="field">
<div class="ui left icon input">
<i class="lock icon"></i>
<input type="password" name="password" placeholder="密码">
</div>
</div>
<button class="ui fluid large teal submit button">登 录</button>
</div>
<div class="ui error mini message"></div>
<div class="ui mini negative message" th:unless="${#strings.isEmpty(message)}" th:text="${message}">用户名密码错误</div>
</form>
</div>
</div>
</div>
</div>
<th:block th:fragment="script">
<script src="https://cdn.jsdelivr.net/npm/aaa@qq.com/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.js"></script>
<script src="../../static/lib/editormd/editormd.min.js" th:src="@{/lib/editormd/editormd.min.js}"></script>
</th:block>
<script>
$('.ui.form').form({
fields : {
username : {
identifier: 'username',
rules: [{
type : 'empty',
prompt: '请输入用户名'
}]
},
password : {
identifier: 'password',
rules: [{
type : 'empty',
prompt: '请输入密码'
}]
}
}
});
</script>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head th:replace="admin/_fragments :: head(~{::title})">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>新闻管理</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.css">
<link rel="stylesheet" href="../../static/css/me.css">
</head>
<body>
<!--导航-->
<nav th:replace="admin/_fragments :: menu(0)" class="ui inverted attached segment m-padded-tb-mini m-shadow-small" >
<div class="ui container">
<div class="ui inverted secondary stackable menu">
<h2 class="ui teal header item">管理后台</h2>
<a href="#" class="active m-item item m-mobile-hide">新闻</a>
<a href="#" class=" m-item item m-mobile-hide">分类</a>
<a href="#" class="m-item item m-mobile-hide">标签</a>
<div class="right m-item m-mobile-hide menu">
<div class="ui dropdown item">
<div class="text">
<img class="ui avatar image" src="../static/images/wechat.jpg">
hualili
</div>
<i class="dropdown icon"></i>
<div class="menu">
<a href="#" class="item">注销</a>
</div>
</div>
</div>
</div>
</div>
<a href="#" class="ui menu toggle black icon button m-right-top m-mobile-show">
<i class="sidebar icon"></i>
</a>
</nav>
<!--中间内容-->
<div class="m-container-small m-padded-tb-big">
<div class="ui container">
<div class="ui success large message">
<h3>Hi,</h3>
<p>hualili,欢迎登录!</p>
</div>
<img src="../static/images/wechat.jpg" alt="" class="ui rounded bordered fluid image">
</div>
</div>
<br>
<br>
<!--底部footer-->
<footer th:replace="admin/_fragments :: footer" class="ui inverted vertical segment m-padded-tb-massive">
<div class="ui center aligned container">
<div class="ui inverted divided stackable grid">
<div class="three wide column">
<div class="ui inverted link list">
<div class="item">
<img src="../../static/images/wechat.jpg" class="ui rounded image" alt="" style="width: 110px">
</div>
</div>
</div>
<div class="three wide column">
<h4 class="ui inverted header m-text-thin m-text-spaced " >最新新闻</h4>
<div class="ui inverted link list">
<a href="#" class="item m-text-thin">用户故事(User Story)</a>
<a href="#" class="item m-text-thin">用户故事(User Story)</a>
<a href="#" class="item m-text-thin">用户故事(User Story)</a>
</div>
</div>
<div class="three wide column">
<h4 class="ui inverted header m-text-thin m-text-spaced ">联系我</h4>
<div class="ui inverted link list">
<a href="#" class="item m-text-thin">Email:hualili@163.com</a>
<a href="#" class="item m-text-thin">QQ:1234567</a>
</div>
</div>
<div class="seven wide column">
<h4 class="ui inverted header m-text-thin m-text-spaced ">news</h4>
<p class="m-text-thin m-text-spaced m-opacity-mini">消息即狭义的新闻,它是对新近发生的有社会意义并引起公众兴趣的事实的简短报道。因此,真实性、时效性及文字少、篇幅小成为消息的基本特征。...</p>
</div>
</div>
<div class="ui inverted section divider"></div>
<p class="m-text-thin m-text-spaced m-opacity-tiny">Copyright © 2016 - 2017 liuhuali Designed by liuhuali</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/aaa@qq.com/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.js"></script>
<script src="../../static/lib/editormd/editormd.min.js" th:src="@{/lib/editormd/editormd.min.js}"></script>
<script>
$('.menu.toggle').click(function () {
$('.m-item').toggleClass('m-mobile-hide');
});
$('.ui.dropdown').dropdown({
on : 'hover'
});
</script>
</body>
</html>
三、分类显示
SSM项目中分页是通过新建了一个PageInfo实体类来实现的,Springboot中是通过@PageableDefault来实现的
TypeController.java
package com.wzx.controller;
import com.wzx.po.Type;
import com.wzx.service.TypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/admin/types")
public class TypeController {
@Autowired
private TypeService typeService;
@RequestMapping
public String list(@PageableDefault(size = 5,sort = {"id"},direction = Sort.Direction.DESC) Pageable pageable, Model model){
Page<Type> page=typeService.listType(pageable);
model.addAttribute("page",page);
return "admin/types";
}
}
TypeService.java
import com.wzx.po.Type;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
import java.util.Optional;
public interface TypeService {
Page<Type> listType(Pageable pageable);
}
TypeServiceImpl.java
package com.wzx.service.impl;
import com.wzx.dao.TypeDao;
import com.wzx.po.Type;
import com.wzx.service.TypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class TypeServiceImpl implements TypeService {
@Autowired
private TypeDao typeDao;
@Override
public Page<Type> listType(Pageable pageable) {
return typeDao.findAll(pageable);
}
}
types.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head th:replace="admin/_fragments :: head(~{::title})">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分类管理</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.css">
<link rel="stylesheet" href="../../static/css/me.css">
</head>
<body>
<!--导航-->
<nav th:replace="admin/_fragments :: menu(2)" class="ui inverted attached segment m-padded-tb-mini m-shadow-small" >
<div class="ui container">
<div class="ui inverted secondary stackable menu">
<h2 class="ui teal header item">管理后台</h2>
<a href="#" class="active m-item item m-mobile-hide">新闻</a>
<a href="#" class=" m-item item m-mobile-hide">分类</a>
<a href="#" class="m-item item m-mobile-hide">标签</a>
<div class="right m-item m-mobile-hide menu">
<div class="ui dropdown item">
<div class="text">
<img class="ui avatar image" src="../static/images/wechat.jpg">
hualili
</div>
<i class="dropdown icon"></i>
<div class="menu">
<a href="#" class="item">注销</a>
</div>
</div>
</div>
</div>
</div>
<a href="#" class="ui menu toggle black icon button m-right-top m-mobile-show">
<i class="sidebar icon"></i>
</a>
</nav>
<div class="ui attached pointing menu">
<div class="ui container">
<div class="right menu">
<a href="#" class="item">新增</a>
<a href="#" class="teal active item">列表</a>
</div>
</div>
</div>
<!--中间内容-->
<div class="m-container-small m-padded-tb-big">
<div class="ui container">
<div class="ui success message" th:unless="${#strings.isEmpty(message)}">
<i class="close icon"></i>
<div class="header">提示:</div>
<p th:text="${message}">恭喜,操作成功!</p>
</div>
<table class="ui celled table">
<thead>
<tr>
<th></th>
<th>名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="type,iterStat:${page.content}">
<td th:text="${iterStat.count}" >1</td>
<td th:text="${type.name}">刻意练习清单</td>
<td>
<a href="#" th:href="@{/admin/types/input/{id}(id=${type.id})}" class="ui mini teal basic button">编辑</a>
<a href="#" th:href="@{/admin/types/delete/{id}(id=${type.id})}" class="ui mini red basic button">删除</a>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="6">
<div class="ui mini pagination menu" th:if="${page.totalPages}>1">
<a class=" item" th:href="@{/admin/types(page=${page.number}-1)}" th:unless="${page.first}" >上一页</a>
<a class=" item" th:href="@{/admin/types(page=${page.number}+1)}" th:unless="${page.last}">下一页</a>
</div>
<a href="#" th:href="@{/admin/types/input/{id}(id=-1)}" class="ui mini right floated teal basic button">新增</a>
</th>
</tr>
</tfoot>
</table>
</div>
</div>
<br>
<br>
<!--底部footer-->
<footer th:replace="admin/_fragments :: footer" class="ui inverted vertical segment m-padded-tb-massive">
<div class="ui center aligned container">
<div class="ui inverted divided stackable grid">
<div class="three wide column">
<div class="ui inverted link list">
<div class="item">
<img src="../../static/images/wechat.jpg" class="ui rounded image" alt="" style="width: 110px">
</div>
</div>
</div>
<div class="three wide column">
<h4 class="ui inverted header m-text-thin m-text-spaced " >最新新闻</h4>
<div class="ui inverted link list">
<a href="#" class="item m-text-thin">用户故事(User Story)</a>
<a href="#" class="item m-text-thin">用户故事(User Story)</a>
<a href="#" class="item m-text-thin">用户故事(User Story)</a>
</div>
</div>
<div class="three wide column">
<h4 class="ui inverted header m-text-thin m-text-spaced ">联系我</h4>
<div class="ui inverted link list">
<a href="#" class="item m-text-thin">Email:liuhuali@163.com</a>
<a href="#" class="item m-text-thin">QQ:liuhuali</a>
</div>
</div>
<div class="seven wide column">
<h4 class="ui inverted header m-text-thin m-text-spaced ">news</h4>
<p class="m-text-thin m-text-spaced m-opacity-mini">消息即狭义的新闻,它是对新近发生的有社会意义并引起公众兴趣的事实的简短报道。因此,真实性、时效性及文字少、篇幅小成为消息的基本特征。...</p>
</div>
</div>
<div class="ui inverted section divider"></div>
<p class="m-text-thin m-text-spaced m-opacity-tiny">Copyright © 2016 - 2017 liuhuali Designed by liuhuali</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/aaa@qq.com/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/semantic-ui/2.2.4/semantic.min.js"></script>
<script src="../../static/lib/editormd/editormd.min.js" th:src="@{/lib/editormd/editormd.min.js}"></script>
<script>
$('.menu.toggle').click(function () {
$('.m-item').toggleClass('m-mobile-hide');
});
$('.ui.dropdown').dropdown({
on : 'hover'
});
//消息提示关闭初始化
$('.message .close')
.on('click', function () {
$(this)
.closest('.message')
.transition('fade');
});
</script>
</body>
</html>
四、运行截图
登录界面
主页面
分类页面
注销页面
上一篇: gecco的模拟登录(仅供学习)
下一篇: Spring Social 开发QQ登录