访问地址:用户登录
代码获取:基于Spring实现博客项目: Spring项目写博客项目
一.项目开发
1.项目开发阶段
- 需求评审,需求分析
- 项目设计(接口设计,DB设计等,比较大的需求,需要设计流程图,用例图,UML, model中的字段)
- 开发+自测
- 提测(提交测试)
- 验收:预发布环境/预生产环境部署测试(开发,测试,产品)
- 上线
2.前端页面
1.登录页面: 根据用户名和密码,进行登录
2.博客列表页:显示所有博客列表,以及显示登录用户的个人信息 3.博客详情页:显示当前博客的详细信息,以及作者信息
4.博客插入/编辑页
3.需求分析
1.登录接口(根据用户名和密码,来判断是否登录成功) 2.根据用户ID,获取用户相关信息
3.获取所有的博客列表
4.根据博客ID,获取博客的详情信息(作者ID) 5.根据博客ID,更新博客内容
6.插入博客
7.删除博客
4.数据库设计
--建表sql
create database if not exists `java_blog_spring` charset utf8mb4;
--用户表
drop table if exists `java_blog_spring`.`user`;
create table `java_blog_spring`.`user` (
`id` int not null auto_increment,
`user_name` varchar(128) not null,
`password` varchar(128) not null,
`github_url` varchar(128) null,
`delete_flag` tinyint(4) null default 0,
`create_time` timestamp null default current_timestamp(),
primary key (`id`),
unique index `user_name_unique` (`user_name` asc))
engine = innodb default character set = utf8mb4 comment = '⽤户表';
--博客表
drop table if exists `java_blog_spring`.`blog`;
create table `java_blog_spring`.`blog` (
`id` int not null auto_increment,
`title` varchar(200) null,
`content` text null,
`user_id` int(11) null,
`delete_flag` tinyint(4) null default 0,
`create_time` timestamp null default current_timestamp(),
primary key (`id`))
engine = innodb default charset = utf8mb4 comment = '博客表';
--新增用户信息
insert into `java_blog_spring`.`user` (`user_name`, `password`,`github_url`)
values("zhangsan","123456","https://gitee.com/bubble-fish666/class-java4
5");
insert into `java_blog_spring`.`user` (`user_name`, `password`,`github_url
`)values("lisi","123456","https://gitee.com/bubble-fish666/class-java45");
insert into `java_blog_spring`.`blog` (`title`,`content`,`user_id`) values
("第一篇博客","111我是博客正文我是博客正文我是博客正文",1);
insert into `java_blog_spring`.`blog` (`title`,`content`,`user_id`) values
("第二篇博客","222我是博客正文我是博客正文我是博客正文",2);
二.Java项目
1.创建Spring项目
创建好之后为以下页面
2.创建实体类
用户实体类
@Data
public class User {
private Integer id;
private String userName;
private String password;
private String githubUrl;
private Byte deleteFlag;
private Date createTime;
}
博客实体类
@Data
public class Blog {
private Integer id;
private String title;
private String content;
private Integer userId;
private Byte deleteFlag;
private Date createTime;
}
3.创建Mapper
userMapper.java
@Mapper
public interface UserMapper {
@Select("select * from user where id=#{id}")
User selectById(Integer id);
@Select("select * from user where user_name=#{name}")
User selectByName(String name);
}
userMapper.xml
blogMapper.java
@Mapper
public interface BlogMapper {
@Select("select * from blog where delete_flag=0")
List selectAll();
@Select("select * from blog where id=#{id} and delete_flag=0")
Blog selectById(Integer id);
Integer updateBlog(Blog blog);
@Insert("insert into blog(content,title,user_id) values(#{content},#{title},#{userId})")
Integer insertBlog(Blog blog);
}
blogMapper.xml
update blog
title=#{title},
content=#{content},
user_id=#{userId},
delete_flag=#{deleteFlag},
where id=#{id};
4.配置文件
application.yml
spring:
profiles:
active: dev
# 日志信息
logging:
file:
path: logs/
level:
root: info
application-dev.yml
server:
port: 8080
# 数据库连接配置
spring:
datasource:
url: jdbc:mysql://localhost:13306/java_blog_spring?characterEncoding=utf8&useSSL=false
username: root
password: woaini520
driver-class-name: com.mysql.cj.jdbc.Driver
# mybatis xml 配置路径
mybatis:
mapper-locations: classpath:mapper/**Mapper.xml
configuration: # 配置打印 MyBatis 执行的 SQL
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true #驼峰转换
application-prod.yml
server:
port: 8080
# 数据库连接配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/java_blog_spring?characterEncoding=utf8&useSSL=false
username: root
password: woaini520
driver-class-name: com.mysql.cj.jdbc.Driver
# mybatis xml 配置路径
mybatis:
mapper-locations: classpath:mapper/**Mapper.xml
configuration:
map-underscore-to-camel-case: true
5.测试类
userMapper
@SpringBootTest
@Slf4j
class UserMapperTest {
@Autowired
UserMapper userMapper;
@Test
void selectById() {
User user = userMapper.selectById(1);
log.info(user.toString());
}
@Test
void selectByName() {
User user = userMapper.selectByName("zhangsan");
log.info(user.toString());
}
}
blogMapper
@SpringBootTest
@Slf4j
class BlogMapperTest {
@Autowired
BlogMapper blogMapper;
@Test
void selectAll() {
List blogs = blogMapper.selectAll();
log.info(blogs.toString());
}
@Test
void selectById() {
Blog blog = blogMapper.selectById(1);
log.info(blog.toString());
}
@Test
void updateBlog() {
Blog blog = new Blog();
blog.setId(1);
blog.setTitle("测试的第一篇博客");
blog.setTitle("测试的第一篇博客的正文内容");
blogMapper.updateBlog(blog);
}
@Test
void insertBlog() {
Blog blog = new Blog();
blog.setTitle("第三篇博客");
blog.setContent("第三篇博客的正文内容");
blog.setUserId(1);
blogMapper.insertBlog(blog);
}
}
6.Common包
1.Result
@Data
public class Result {
//业务处理状态码 200成功
2.ErrorAdvice(统一异常返回)
@ControllerAdvice
public class ErrorAdvice {
@ExceptionHandler
public Result error(Exception e) {
return Result.fail(-1, e.getMessage());
}
}
3.统一返回格式处理
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@SneakyThrows
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof Result) {
return body;
}
if (body instanceof String) {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(Result.success(body));
}
return Result.success(body);
}
}
7.导入前端代码
前端代码在这取:基于Spring实现博客项目: Spring项目写博客项目
三.业务代码
1.约定前后端交互接口
[请求]
/blog/getlist
[响应]
[
{
blogId: 1,
title: “第⼀篇博客”,
content: “博客正⽂”,
userId: 1,
postTime: “2021-07-07 12:00:00”
},
{
blogId: 2,
title: “第⼆篇博客”,
content: “博客正⽂”,
userId: 1,
postTime: “2021-07-07 12:10:00”
},
2.Service层
UserService
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private BlogMapper blogMapper;
public User selectById(Integer id) {
return userMapper.selectById(id);
}
public User selectByName(String name) {
return userMapper.selectByName(name);
}
public User getAuthorInfoByBlogId(Integer id) {
Blog blog = blogMapper.selectById(id);
if (blog == null || blog.getUserId()
BlogService
@Service
public class BlogService {
@Autowired
private BlogMapper blogMapper;
public List getAll() {
return blogMapper.selectAll();
}
public Blog getBlogById(Integer id) {
return blogMapper.selectById(id);
}
public Integer updateBlog(Blog blog) {
return blogMapper.updateBlog(blog);
}
public Integer addBlog(Blog blog) {
return blogMapper.insertBlog(blog);
}
}
3.Controller层
BlogController
@RestController
@RequestMapping("/blog")
public class BlogController {
@Autowired
BlogService blogService;
@RequestMapping("/getlist")
public List getBlogList() {
return blogService.getAll();
}
@RequestMapping("/getBlogDetail")
public Result getBlogDetail(Integer id, HttpSession httpSession) {
if (id == null || id
UserController
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
@RequestMapping("/login")
public Result login(HttpServletRequest request, String username, String password) {
//参数校验
if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) {
return Result.fail(-2, "账号或密码不能为空");
}
//密码校验
User user = userService.selectByName(username);
if (user == null || !user.getPassword().equals(password)) {
return Result.fail(-3, "用户名不存在或者密码错误");
}
//参数返回
user.setPassword("");
HttpSession session = request.getSession(true);
session.setAttribute(Constants.USER_INFO_SESSION, user);
return Result.success("登陆成功");
}
@RequestMapping("/getUserInfo")
public Result getUserInfo(HttpSession session) {
if (session == null || session.getAttribute(Constants.USER_INFO_SESSION) == null) {
return Result.fail(-1, "用户未登录");
}
return Result.success(session.getAttribute(Constants.USER_INFO_SESSION));
}
@RequestMapping("/getAuthorInfo")
public Result getAuthorInfoByBlogId(@RequestParam("id") Integer blogId) {
if (blogId == null || blogId
4.登录接口拦截器
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute(Constants.USER_INFO_SESSION) == null) {
response.setStatus(401);
return false;
}
return true;
}
}
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
private final List excludes = Arrays.asList(
"/**/*.html",
"/blog-editormd/**",
"/css/**",
"/js/**",
"/pic/**",
"/user/login"
);
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor).
addPathPatterns("/**"). //拦截所有路径
excludePathPatterns(excludes);
}
}
在blog_list.html和blog_detail的ajax请求添加
error: function (error) {
if (error != null && error.status == 401) {
location.assign("/blog_login.html");
}
}
四.前端代码
有些代码重复出现,可以抽象为一个函数,我们放在./js/common.js中
function logout() {
$("#logout").click(function () {
$.ajax({
type: "get",
url: "/user/logout",
success: function (result) {
if (result != null && result.data == true) {
location.assign("/blog_login.html")
}
},
})
})
}
1.blog_list.html
先来个前置知识:日期格式化
方式一:将日期格式改为(java.sql.Date适用)
private Timestamp createTime;
然后引入js包
function formatDate(time) {
var date = new Date(time);
var year = date.getFullYear(),
month = date.getMonth() + 1,//月份是从0开始的
day = date.getDate(),
hour = date.getHours(),
min = date.getMinutes(),
sec = date.getSeconds();
var newTime = year + '-' +
(month
直接进行转化即可
formatDate(blog.createTime)
方式二:(java.util.Date适用)
工具类
public class DateUtils {
public static String formatDate(Date date) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(date);
}
}
博客实体类
@Data
public class Blog {
private Integer id;
private String title;
private String content;
private Integer userId;
private Byte deleteFlag;
private Date createTime;
public String getCreateTime() {
return DateUtils.formatDate(createTime);
}
}
此时就不需要多余的操作了
finalHtml += ''+blog.createTime+'';
之后javascrip代码
$(function () {
$.ajax({
type: "get",
url: "/blog/getlist",
success: function (result) {
var finalHtml = "";
if (result.code == 200 && result.data != null && result.data.length > 0) {
var dataHtml = result.data;
for (var i = 0; i < dataHtml.length; ++i) {
var blog = dataHtml[i];
finalHtml += '';
finalHtml += '' + blog.title + '
服务器托管,北京服务器托管,服务器租用,机房机柜带宽租用
咨询:董先生
电话13051898268 QQ/微信93663045!
上一篇: MySQL事务死锁问题排查 | 京东云技术团队
下一篇: Vitess全局唯一ID生成的实现方案 | 京东云技术团队