• 可以帮助我们构建项目、管理项目中的jar包
• Maven仓库:存放构件的位置
- 本地仓库:默认是 ~/.m2/repository
- 远程仓库:中央仓库、镜像仓库、私服仓库
• 示例:安装、配置、常用命令
http://maven.apache.org
项目构建的总体思路是:先编写数据库(SQL,实体类),dao层(mapper接口,mapper.xml),service层
数据库创建的细节在项目总结-1
package com.think.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
//实体类:讨论帖
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DiscussPost {
private int id;
private String userId;
private String title;
private String context;
private int type;
private int status;
private Date createTime;
private int commentCount;
private Double score;
}
public class User {
private int id;
private String username;
private String password;
private String salt;
private String email;
private int type;
private int status;
private String activationCode;
private String headerUrl;
private Date createTime;
}
@Mapper
@Repository
public interface DiscussPostMapper {
/**
* 查询用户的帖子:支持分页查询
* @param userId 当userId = 0,查询所有人发布的帖子;当userId != 0,根据userId查询帖子
* @param offset 每页起始行的行号
* @param limit 每页最多显示多少的帖子
* @return 返回值即用户发布的帖子
*/
List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit);
/**
* 为了实现分页查询,获取全部帖子的数量
* @param userId 当userId = 0,查询所有人发布的帖子;当userId != 0,根据userId查询帖子
* @return 全部帖子的数量
*/
//@Param 注解用于给参数起别名
//如果只有一个参数,并且会在里使用[即动态SQL],则必须添加别名
int selectDiscussPostRows(@Param("userId") int userId);
}
package com.think.dao;
import com.think.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface UserMapper {
User selectById(int id);
User selectByName(String username);
User selectByEmail(String email);
int insertUser(User user);
int updateStatus(int id, int status);
int updateHeader(int id, String headerUrl);
int updatePassword(int id, String password);
}
<mapper namespace="com.think.dao.DiscussPostMapper">
<sql id="selectFields">
id,user_id,title,context,type,status,create_time,comment_count,score
sql>
<select id="selectDiscussPosts" resultType="DiscussPost">
select <include refid="selectFields"/>
from discuss_post
where status != 2 /*status为帖子的状态,当status=2时,表示该帖已经被拉黑*/
<if test="userId != 0"> /*动态SQL,当userId != 0需要根据userId查询帖子;userId=0时,查询全部的帖子*/
and user_id = #{userId}
if>
order by type desc,create_time desc /*type为帖子类型,type=0表示置顶。因此首先根据type降序排序,再根据create_time排序*/
limit #{offset},#{limit} /*利用SQL的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>
<mapper namespace="com.nowcoder.community.dao.UserMapper">
<sql id="insertFields">
username, password, salt, email, type, status, activation_code, header_url, create_time
sql>
<sql id="selectFields">
id, username, password, salt, email, type, status, activation_code, header_url, create_time
sql>
<select id="selectById" resultType="User">
select <include refid="selectFields">include>
from user
where id = #{id}
select>
<select id="selectByName" resultType="User">
select <include refid="selectFields">include>
from user
where username = #{username}
select>
<select id="selectByEmail" resultType="User">
select <include refid="selectFields">include>
from user
where email = #{email}
select>
<insert id="insertUser" parameterType="User" keyProperty="id">
insert into user (<include refid="insertFields">include>)
values(#{username}, #{password}, #{salt}, #{email}, #{type}, #{status}, #{activationCode}, #{headerUrl}, #{createTime})
insert>
<update id="updateStatus">
update user set status = #{status} where id = #{id}
update>
<update id="updateHeader">
update user set header_url = #{headerUrl} where id = #{id}
update>
<update id="updatePassword">
update user set password = #{password} where id = #{id}
update>
mapper>
package com.think.service;
import com.think.dao.DiscussPostMapper;
import com.think.entity.DiscussPost;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service //注入spring容器
public class DiscussPostService {
//service需要调用dao,因此将DiscussPostMapper导入
@Autowired(required = false)
private DiscussPostMapper discussPostMapper;
//service层的方法
//当业务比较简单时,service与mapper类似,只需要调用dao的方法
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);
}
}
package com.think.service;
import com.think.dao.UserMapper;
import com.think.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
//根据userId查询用户
public User fingUserById(int id){
return userMapper.selectById(id);
}
}
Index.html
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" href="https://static.nowcoder.com/images/logo_87_87.png"/>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous">
<link rel="stylesheet" th:href="@{/css/global.css}" />
<title>牛客网-首页title>
head>
<body>
<div class="nk-container">
<header class="bg-dark sticky-top" th:fragment="header">
<div class="container">
<nav class="navbar navbar-expand-lg navbar-dark">
<a class="navbar-brand" href="#">a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon">span>
button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item ml-3 btn-group-vertical">
<a class="nav-link" th:href="@{/index}">首页a>
li>
<li class="nav-item ml-3 btn-group-vertical">
<a class="nav-link position-relative" href="site/letter.html">消息<span class="badge badge-danger">12span>a>
li>
<li class="nav-item ml-3 btn-group-vertical">
<a class="nav-link" th:href="@{/register}">注册a>
li>
<li class="nav-item ml-3 btn-group-vertical">
<a class="nav-link" th:href="@{/login}">登录a>
li>
<li class="nav-item ml-3 btn-group-vertical dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img src="http://images.nowcoder.com/head/1t.png" class="rounded-circle" style="width:30px;"/>
a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item text-center" href="site/profile.html">个人主页a>
<a class="dropdown-item text-center" href="site/setting.html">账号设置a>
<a class="dropdown-item text-center" href="site/login.html">退出登录a>
<div class="dropdown-divider">div>
<span class="dropdown-item text-center text-secondary">nowcoderspan>
div>
li>
ul>
<form class="form-inline my-2 my-lg-0" action="site/search.html">
<input class="form-control mr-sm-2" type="search" aria-label="Search" />
<button class="btn btn-outline-light my-2 my-sm-0" type="submit">搜索button>
form>
div>
nav>
div>
header>
<div class="main">
<div class="container">
<div class="position-relative">
<ul class="nav nav-tabs mb-3">
<li class="nav-item">
<a class="nav-link active" href="#">最新a>
li>
<li class="nav-item">
<a class="nav-link" href="#">最热a>
li>
ul>
<button type="button" class="btn btn-primary btn-sm position-absolute rt-0" data-toggle="modal" data-target="#publishModal">我要发布button>
div>
<div class="modal fade" id="publishModal" tabindex="-1" role="dialog" aria-labelledby="publishModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="publishModalLabel">新帖发布h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×span>
button>
div>
<div class="modal-body">
<form>
<div class="form-group">
<label for="recipient-name" class="col-form-label">标题:label>
<input type="text" class="form-control" id="recipient-name">
div>
<div class="form-group">
<label for="message-text" class="col-form-label">正文:label>
<textarea class="form-control" id="message-text" rows="15">textarea>
div>
form>
div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消button>
<button type="button" class="btn btn-primary" id="publishBtn">发布button>
div>
div>
div>
div>
<div class="modal fade" id="hintModal" tabindex="-1" role="dialog" aria-labelledby="hintModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="hintModalLabel">提示h5>
div>
<div class="modal-body" id="hintBody">
发布完毕!
div>
div>
div>
div>
<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>
div>
div>
<footer class="bg-dark">
<div class="container">
<div class="row">
<div class="col-4 qrcode">
<img src="https://uploadfiles.nowcoder.com/app/app_download.png" class="img-thumbnail" style="width:136px;" />
div>
<div class="col-8 detail-info">
<div class="row">
<div class="col">
<ul class="nav">
<li class="nav-item">
<a class="nav-link text-light" href="#">关于我们a>
li>
<li class="nav-item">
<a class="nav-link text-light" href="#">加入我们a>
li>
<li class="nav-item">
<a class="nav-link text-light" href="#">意见反馈a>
li>
<li class="nav-item">
<a class="nav-link text-light" href="#">企业服务a>
li>
<li class="nav-item">
<a class="nav-link text-light" href="#">联系我们a>
li>
<li class="nav-item">
<a class="nav-link text-light" href="#">免责声明a>
li>
<li class="nav-item">
<a class="nav-link text-light" href="#">友情链接a>
li>
ul>
div>
div>
<div class="row">
<div class="col">
<ul class="nav btn-group-vertical company-info">
<li class="nav-item text-white-50">
公司地址:北京市朝阳区大屯路东金泉时代3-2708北京牛客科技有限公司
li>
<li class="nav-item text-white-50">
联系方式:010-60728802(电话) [email protected]
li>
<li class="nav-item text-white-50">
牛客科技©2018 All rights reserved
li>
<li class="nav-item text-white-50">
京ICP备14055008号-4
<img src="http://static.nowcoder.com/company/images/res/ghs.png" style="width:18px;" />
京公网安备 11010502036488号
li>
ul>
div>
div>
div>
div>
div>
footer>
div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous">script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" crossorigin="anonymous">script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" crossorigin="anonymous">script>
<script th:src="@{/js/global.js}">script>
<script th:src="@{js/index.js}">script>
body>
html>
编写首页controller,返回首页
package com.guo.controller;
import com.guo.entity.DiscussPost;
import com.guo.entity.User;
import com.guo.service.DiscussPostService;
import com.guo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
public class HomeController {
@Autowired
private DiscussPostService discussPostService;
@Autowired
private UserService userService;
@RequestMapping(path = "/index", method = RequestMethod.GET)
public String getIndexPage(Model model) {
List<DiscussPost> list = discussPostService.findDiscussPosts(0, 0, 10);
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";
}
}
此时访问http://localhost:8080/community/index
首页已经有雏形