首先,web项目主要解决的就是浏览器和服务器之间的交互,开发流程就是1次请求的执行过程,任何功能都可以拆解成若干次请求。
按照依赖顺序Dao->Service->Controller
以实现社区首页显示前10个帖子功能为例
1.在数据库中建表
2.在/entity包下创建实体类
实体类的作用是封装表里的数据,命名为大写驼峰式,eg:DiscussPost.java
private int userId;
PS:字段名称为user_id,属性名为userId
package com.nowcoder.community.entity;
import java.util.Date;
public class DiscussPost {
private int id;
private int userId;
private String title;
private String content;
private int type;
private int status;
private Date createTime;
private int commentCount;
private double score;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
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 int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public int getCommentCount() {
return commentCount;
}
public void setCommentCount(int commentCount) {
this.commentCount = commentCount;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "DiscussPost{" +
"id=" + id +
", userId=" + userId +
", title='" + title + '\'' +
", content='" + content + '\'' +
", type=" + type +
", status=" + status +
", createTime=" + createTime +
", commentCount=" + commentCount +
", score=" + score +
'}';
}
}
3.开发数据访问组件Mapper
要实现某个功能,要在mapper接口中声明查询方法,
并在配置文件mapper.xml中写出与之有关的SQL。
@Mapper
public interface DiscussPostMapper {
//分页查询帖子功能,返回的是多条数据的是一个集合,集合里装的是帖子的对象
//方法名自己取,参数是userId,帖子表有userId字段
//首页查询不需要传入userId,默认为0,当userId为0时不管,不拼到SQL中
//不为0时,正常拼到SQL中,SQL是动态的SQL
//分页功能:MySQL数据库实现只需要设置limit参数:起始行行号offset,这一页最多显示多少条数据limit
List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit);
//一共有多少页:一共多少页,每页显示多少条数据
//查询表里一共多少行数据功能
//@Param("userId") 用于给参数起别名,比如有的参数名称比较长
//如果只有一个参数,并且在里使用,则必须要加别名
//如果在SQL中需要用到动态的拼接条件,条件里需要用到参数,且方法只有一个参数,参数必须要起别名
int selectDiscussPostRows(@Param("userId") int userId);
}
<sql id="selectFields">
id, user_id, title, content, type, status, create_time, comment_count, score
sql>
<include refid="selectFields">include>
<select id="selectDiscussPosts" resultType="DiscussPost">select>
<if test="userId!=0">
and user_id = #{userId}
if>
//字段=#{参数}
user_id = #{userId}
完整代码:
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nowcoder.community.dao.DiscussPostMapper">
<sql id="selectFields">
id, user_id, title, content, type, status, create_time, comment_count, score
sql>
<select id="selectDiscussPosts" resultType="DiscussPost">
select <include refid="selectFields">include>
from discuss_post
where status != 2
<if test="userId!=0">
and user_id = #{userId}
if>
order by type desc, create_time desc
limit #{offset}, #{limit}
select>
<select id="selectDiscussPostRows" resultType="int">
select count(id)
from discuss_post
where status !=2
<if test="userId!=0">
and user_id = #{userId}
if>
select>
mapper>
4.在/test/…目录下创建测试类MapperTests.java
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class MapperTests {
@Autowired
private UserMapper userMapper;
@Autowired
private DiscussPostMapper discussPostMapper;
@Test
public void testSelectUser(){
User user = userMapper.selectById(101);
System.out.println(user);
user = userMapper.selectByName("liubei");
System.out.println(user);
user = userMapper.selectByEmail("[email protected]");
System.out.println(user);
}
@Test
public void testInsertUser(){
User user = new User();
user.setUsername("test");
user.setPassword("123456");
user.setSalt("abc");
user.setEmail("[email protected]");
user.setHeaderUrl("https://www.nowcoder.com/101.png");
user.setCreatTime(new Date());
int rows = userMapper.insertUser(user);
System.out.println(rows);
System.out.println(user.getId());
}
@Test
public void updateUser(){
int rows = userMapper.updateStatus(150,1);
System.out.println(rows);
rows = userMapper.updateHeader(150,"https://www.nowcoder.com/102.png");
System.out.println(rows);
rows = userMapper.updatePassword(150,"hello");
System.out.println(rows);
}
@Test
public void testSelectPosts(){
List<DiscussPost> list = discussPostMapper.selectDiscussPosts(149,0,10);
for (DiscussPost post : list){
System.out.println(post);
}
int rows = discussPostMapper.selectDiscussPostRows(149);
System.out.println(rows);
}
}
在/service包下新建业务组件DiscussPostService.java和UserSevice.java
@Service
public class DiscussPostService {
@Autowired
private DiscussPostMapper discussPostMapper;
public List<DiscussPost> findDiscussPosts(int userId, int offset, int limit){
return discussPostMapper.selectDiscussPosts(userId, offset, limit);
}
public int findDiscussPostRows(int userId){
return discussPostMapper.selectDiscussPostRows(userId);
}
}
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
//根据用户id查询用户的方法
public User findUserById(int id){
return userMapper.selectById(id);
}
}
@Controller
public class HomeController {
@Autowired
private DiscussPostService discussPostService;
@Autowired
private UserService userService;
@RequestMapping(path = "/index", method = RequestMethod.GET)
List<DiscussPost> list = discussPostService.findDiscussPosts(0, page.getOffset(), page.getLimit());
//遍历DiscussPost,根据每一个userId查user
//封装DiscussPost和User对象
List<Map<String, Object>> discussPosts = new ArrayList<>();
if(list != null){
for (DiscussPost post : list){
Map<String, Object> map = new HashMap<>();
map.put("post", post);
User user = userService.findUserById(post.getUserId());
map.put("user", user);
discussPosts.add(map);
}
}
model.addAttribute("discussPosts",discussPosts);
return "/index";
}
}
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<link rel="stylesheet" th:href="@{css/global.css}" />
<link rel="icon" href="https://static.nowcoder.com/images/logo_87_87.png"/>
th:each="map:${discussPosts}"
th:src="${map.user.headerUrl}"
表示
map.get("user")->User->user.getHeaderUrl()
th:utext="${map.post.title}"
th:if="${map.post.type==1}"
th:text="${#dates.format(map.post.createTime,'yyyy-MM-dd HH:mm:ss')}"
完整代码:
<ul class="list-unstyled">
<li class="media pb-3 pt-3 mb-3 border-bottom" th:each="map:${discussPosts}">
<a href="site/profile.html">
<img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle" alt="用户头像" style="width:50px;height:50px;">
a>
<div class="media-body">
<h6 class="mt-0 mb-3">
<a href="#" th:utext="${map.post.title}">备战春招,面试刷题跟他复习,一个月全搞定!a>
<span class="badge badge-secondary bg-primary" th:if="${map.post.type==1}">置顶span>
<span class="badge badge-secondary bg-danger" th:if="${map.post.status==1}">精华span>
h6>
<div class="text-muted font-size-12">
<u class="mr-3" th:utext="${map.user.username}">寒江雪u> 发布于 <b th:text="${#dates.format(map.post.createTime,'yyyy-MM-dd HH:mm:ss')}">2019-04-15 15:32:18b>
<ul class="d-inline float-right">
<li class="d-inline ml-2">赞 11li>
<li class="d-inline ml-2">|li>
<li class="d-inline ml-2">回帖 7li>
ul>
div>
div>
li>
ul>