尚硅谷微头条案例

一.资料

1.完整项目: 

github项目地址

2.测试工具-postman

https://www.getpostman.com

3.WEB服务器-tomcat-10.1.18

Apache Tomcat® - Welcome!

4.java第三方库

Central Repository: (maven.org)

5.IDEA

idea破解版安装与配置

6.百度网盘资料

尚硅谷javaWeb百度网盘资料

7.biliblili

bilibili对应的尚硅谷学习视频
       

二.准备

1.tomcat安装与部署:

b站:p56-p59

下载

1.百度网盘

资料下面的software目录下有tomcat安装包,同时含有postman,vscode等安装包

2.通过上面的链接下载,版本有所差异

安装和配置

-正确安装JDK并配置JAVA_HOME(以JDK17为例 https://injdk.cn中可以下载各种版本的JDK)

-解压tomcat到非中文无空格目录

-点击bin/startup.bat启动

-控制台出现乱码?

第4步给出答案

-打开浏览器输入 http://localhost:8080访问测试,出现以下画面说明tomcat配置成功

-直接关闭窗口或者运行 bin/shutdown.bat关闭tomcat

2.IDEA关联并部署tomcat

b站:p60-p61

3.Web项目搭建

p62

2,3后续单独更一期

4.乱码问题

b站:p85-p88

1.查看输出日志控制台的编码格式

2.进入tomcat目录下的config文件

3.找到logging.properties文件,里面可以设置日志的编码格式

5.如何使用postman?

b站: p184

下载注册后进入postman首页

1.创建一个存放测试数据的文件

点击"+"号,点击Blank collection,设置文件名称即可

2.点击“+”号,就可以发送请求了

3.样例

二.功能简介

  • 用户功能

    • 注册功能

    • 登录功能

  • 头条新闻

    • 新闻的分页浏览

    • 通过标题关键字搜索新闻

    • 查看新闻详情

    • 新闻的修改和删除

  • 权限控制

    • 用户只能修改和自己发布的头条新闻

三.数据库设计

mysql-8.0.32


  • news_headline 新闻详细信息表

    • hid int -新闻id -主键

    • title varchar -标题

    • article varchar-内容

    • publisher int -作者

    • page_views int -浏览量

    • type int -新闻类型id

    • create_time datetime -发布时间

    • update_time datetime-更新时间

    • is_deleted int -是否被删除

  • news_type - 新闻类型表

    • tid int -新闻类型id -主键

    • tname varchar -新闻类型名称

  • news_user -用户表

    • uid int -用户id -主键

    • username varchar -用户名

    • user_pwd varchar 密码

    • nick_name varchar 昵称

四.后端项目结构

  • src
    • util 工具类包,主要存放一些工具类

      • MD5Util 加密工具类

      • JDBCUtil连接池工具类

      • JwtHelper 处理token相关信息

      • WebUtil 处理json数据

    • test 测试代码

    • service 服务层, 主要用于处理业务逻辑

      • Impl 实现类

        • NewsUserServiceImpl

        • NewsHeadlineServiceImpl

        • NewsTypeServiceImpl

      • interface NewsUserService

      • interface NewsHeadlineService

      • interface NewsTypeService

    • pojo 实体类层 ,存放实体类

      • package-vo

        • HeadlineQueryVo 带条件查询,关键字封装

        • HeadlinePageVo 封装响应给客户端的数据

        • HeadlineDetail 显示新闻详情

      • NewsUser

      • NewsHeadline

      • NewsType

    • filters 过滤器包, 存放过滤器代码

      • CrosFilter 跨域过滤器,解决跨域问题

      • LoginFilter 检验登陆状态

    • dao 数据访问层,主要用于定义对各个表格的curd方法

      • impl 存放实现类

        • NewsUserDaoImpl

        • NewsTypeDaoImpl

        • NewsHeadlineDaoImpl

      • BaseDao 操作数据库

      • interface NewsUserDao

      • interface NewsTypeDao

      • interface NewsHeadlineDao

    • controller 控制层代码,主要由Servlet组成

      • BaseControl 使用不同方法控制不同请求

      • NewsHeadlineControl 管理新闻

      • NewsUserControler 管理用户

      • NewsTypeControler 管理新闻类型

      • ProptalController 门户控制器,未登录状态下访问信息

    • common 公共包

      • Result 异步响应格式类

      • ResultCodeEnum 枚举类,枚举后端响应状态

    • resources

      • jdbc.properties 数据库连接相关配置信息

五.请求参数获取及响应

主要展示请求信息,代码细节 在 百度网盘 或 github中 08_第八章 微头条项目开发.md 文件

(零) util&comman类

JDBCUtil

       -BaseDao类中用到,连接数据库

       --Connection connection = JDBCUtil.getConnection();

JwtHelper

        -登录成功或生成token,NewsUserControl类中login方法用到

        --String JwtHelper.createToken(Long uid) 创建token

        --Long JwtHelper.getUserId(String token) 通过token获取uid

        --boolean JwtHelper.isExpiration() token 是否过期=过期?ture:false     

MD5Util

        -加密用户密码

        --String MD5Util.encrypt(String userPwd)

WEBUtil

        -读取JSON串

        --WEBUtil.readJson()

        --WEBUtil.WriteJson()

(一)登录

1.点击登录后  

客户端


发送请求: uri:user/login

请求方式:

        POST

请求头:

        无

请求体:

JSON格式

响应示例:

  • 登录成功

{
    "code":"200",         // 成功状态码 
    "message":"success"   // 成功状态描述
    "data":{
        "token":"... ..." // 用户id的token
    }
}
  • 用户名有误

{
    "code":"501",
    "message":"用户名有误"
    "data":{}
}
  • 密码有误

{
    "code":"503",
    "message":"密码有误"
    "data":{}
}

后端


@WebServlet("/user/*") //通过注解配置映射路径,表示在user下进行模糊匹配
public class NewsUserControl extends BaseController{ 
    //BaseController 中重写了service方法,通过反射获取uri中的路径最后一位并调用该方法
    //例如:uri = user/login,BaseController则获取login,通过反射调用NewsUserControl 
    //下的login方法
    //调用NewsUserService接口完成参数处理工作
    private NewsUserService newsUserService= new NewsUserServiceImpl();
    protected void login(HttpServletRequest req, HttpServletResponse resp) {
        //接收JSON数据 -调用WEBUtil方法的readJson获取NewsUser对象
        NewsUser newsUser = WEBUtil.readJson(req, NewsUser.class);
        
        //登录验证
            //创建Result对象
            //密码使用MD5Util.entry()加密
            //判断账号和密码
            //如果登录成功将通过JwtHelp生成token存入map中 {"data":token}
            //将结果以map形式封装到Result对象
        Result result = null;
        //判断用户名
        if(loginUser != null) {
            //判断密码
            if(loginUser.getUserPwd().equals(MD5Util.encrypt(newsUser.getUserPwd()))) {
                //密码正确
                Map<String,Object> data = new HashMap<String,Object>();
                //生成token
                String token = JwtHelper.createToken(loginUser.getUid().longValue());
                //封装结果
                data.put("token", token);
                result = Result.ok(data);
            }else{
                //密码错误
                result = Result.build(null, ResultCodeEnum.PASSWORD_ERROR);
            }
        }else{
            // 封装用户名错误结果
            result=Result.build(null, ResultCodeEnum.USERNAME_ERROR);
        }
        //响应结果JSON格式
            //通过WEBUtil.writeJson()将生成的token发送到前端
        //响应结果
        WEBUtil.writeJson(resp,result);

    }
}

2.登录成功后

客户端


发送请求: uri:user/getUserInfo

请求方式:

        GET

请求头:

        

token:......

请求体:

        无

响应示例

  • 成功获取

{
    "code": 200,
    "message": "success",
    "data": {
        "loginUser": {
            "uid": 1,
            "username": "zhangsan",
            "userPwd": "",
            "nickName": "张三"
        }
    }
}
  • 获取失败

{
    "code": 504,
    "message": "notLogin",
    "data": null
}

 后端


@WebServlet("/user/*") //通过注解配置映射路径,表示在user下进行模糊匹配
public class NewsUserControl extends BaseController{ 
    protected void getUserInfo(HttpServletRequest req, HttpServletResponse resp) {
        //String token = req.getParameter("token");
        //从请求头中获取用户信息,而不是请求体
        String token = req.getHeader("token");
        if(null != token){
            if(!JwtHelper.isExpiration(token)){
                Integer uid = JwtHelper.getUserId(token).intValue();
                //token没过期且不为空
                NewsUser newsUser = newsUserService.findByUserId(uid);
                //获取用户信息
                newsUser.setUserPwd("");
                Map<String,NewsUser> data = new HashMap<>();
                data.put("loginUser",newsUser);
                result = Result.ok(data);
            }
        }
        WEBUtil.writeJson(resp,result);

    }

}

(二)注册

1.注册时用户名占用校验

客户端


发送请求: uri:user/checkUserName

请求方式:

        POST

请求头:

        无

请求体:

键值对

        

响应示例

  • 用户名校验通过

{
    "code":"200",
    "message":"success"
    "data":{}
}
  • 用户名占用

{
    "code":"505",
    "message":"用户名占用"
    "data":{}

 后端


@WebServlet("/user/*") //通过注解配置映射路径,表示在user下进行模糊匹配
public class NewsUserControl extends BaseController{ 
    protected void checkUserName(HttpServletRequest req, HttpServletResponse resp) {
        //前端传来的是键值对,则可以通过getParameter(key)的方式获取数据
        String username = req.getParameter("username");
        NewsUser newsUser = newsUserService.findByUserName(username);
        Result result=null;
        if (null == newsUser){ //用户名未被占用
            result=Result.ok(null);
        }else{
            result=Result.build(null,ResultCodeEnum.USERNAME_USED);
        }
        WEBUtil.writeJson(resp,result);

    }

}

(二)注册表单提交

客户端


发送请求: uri:user/regist

请求方式:

        POST

请求头:

        无

请求体:

JSON

        ​​

响应示例

  • 注册成功

{
    "code":"200",
    "message":"success"
    "data":{}
}
  • 用户名占用

{
    "code":"505",
    "message":"用户名占用"
    "data":{}
}

  后端


@WebServlet("/user/*") //通过注解配置映射路径,表示在user下进行模糊匹配
public class NewsUserControl extends BaseController{ 
     protected void regist(HttpServletRequest req, HttpServletResponse resp) {
        NewsUser register = WEBUtil.readJson(req, NewsUser.class);
        //校验用户名是否被占用
        NewsUser newsUser = newsUserService.findByUserName(register.getUsername());
        Result result = null;
        if(newsUser == null){
            //用户名未被占用
            newsUserService.registUser(register);
            result = Result.ok(null);

        }else{
            result = Result.build(null,ResultCodeEnum.USERNAME_USED);
        }
        WEBUtil.writeJson(resp, result);
    }

}

(三)微头条首页

客户端


发送请求: uri:portal/findAllTypes

请求方式:

        GET

请求头:

        无

请求体:

        无

响应示例

List<NewsType>

        {
    "code":"200",
     "message":"OK"
     "data:
            [   
                {
                    "tid":"1",
                    "tname":"新闻"
                },
                {
                    "tid":"2",
                    "tname":"体育"
                },
                {
                    "tid":"3",
                    "tname":"娱乐"
                },
                {
                    "tid":"4",
                    "tname":"科技"
                },
                {
                    "tid":"5",
                    "tname":"其他"
                }
            ]
   
}

  后端


@WebServlet("/portal/*")
public class PortalController extends BaseController {
    protected void findAllTypes(HttpServletRequest req, HttpServletResponse resp) {
        List<NewsType> newsTypeList = newsTypeService.findAll();
        WEBUtil.writeJson(resp, Result.ok(newsTypeList));
    }

}

(四)分页带条件查询所有头条

客户端

发送请求: uri:portal/findAllTypes

请求方式:

        GET

请求头:

        无

请求体:

        无

响应示例

{
    "code":"200",
    "message":"success"
    "data":{
        "pageInfo":{
            "pageData":[                           // 本页的数据
                {
                    "hid":"1",                     // 新闻id 
                    "title":"尚硅谷宣布 ... ...",   // 新闻标题
                    "type":"1",                    // 新闻所属类别编号
                    "pageViews":"40",              // 新闻浏览量
                    "pastHours":"3" ,              // 发布时间已过小时数
                    "publisher":"1"                // 发布用户ID
                },
                {
                    "hid":"1",                     // 新闻id 
                    "title":"尚硅谷宣布 ... ...",   // 新闻标题
                    "type":"1",                    // 新闻所属类别编号
                    "pageViews":"40",              // 新闻浏览量
                    "pastHours":"3",              // 发布时间已过小时数
                    "publisher":"1"                // 发布用户ID
                },
                {
                    "hid":"1",                     // 新闻id 
                    "title":"尚硅谷宣布 ... ...",   // 新闻标题
                    "type":"1",                    // 新闻所属类别编号
                    "pageViews":"40",              // 新闻浏览量
                    "pastHours":"3",               // 发布时间已过小时数
                    "publisher":"1"                // 发布用户ID
                }
            ],
            "pageNum":1,    //页码数
            "pageSize":10,  // 页大小
            "totalPage":20, // 总页数
            "totalSize":200 // 总记录数
        }
    }
}

   后端


@WebServlet("/portal/*")
public class PortalController extends BaseController {
    protected void findNewsPage(HttpServletRequest req, HttpServletResponse resp) {
        //读取数据
        HeadlineQueryVo headLineQueryVo = WEBUtil.readJson(req, HeadlineQueryVo.class);
        
        Map<String,Object> pageInfo = newsHeadlineService.findPage(headLineQueryVo);
        Map<String,Object> pageInfoMap = new HashMap<String,Object>();
        pageInfoMap.put("pageInfo", pageInfo);
        //返回数据
        //pageInfo 的类型为 List<HeadlinePageVo>
        //{"pageInfo":{pageData,"pageNum","pageSize","totalPage","totalSize"}}

        WEBUtil.writeJson(resp,Result.ok(pageInfoMap));

    }

}

(五)查看头条详情

客户端

发送请求: uri:portal/HeadlineDetail

请求方式:

        POST

请求头:

        无

请求体:

键值对

响应示例

{
    "code":"200",
    "message":"success",
    "data":{
        "headline":{
            "hid":"1",                     // 新闻id 
            "title":"马斯克宣布 ... ...",   // 新闻标题
            "article":"... ..."            // 新闻正文
            "type":"1",                    // 新闻所属类别编号
            "typeName":"科技",             // 新闻所属类别
            "pageViews":"40",              // 新闻浏览量
            "pastHours":"3" ,              // 发布时间已过小时数
            "publisher":"1" ,               // 发布用户ID
            "author":"张三"                 // 新闻作者
        }
    }
}

  后端


@WebServlet("/portal/*")
public class PortalController extends BaseController {
        protected void showHeadlineDetail(HttpServletRequest req, HttpServletResponse resp)            {
        //注释消失了(狗头),具体见资料(上面)
        Integer hid = Integer.parseInt(req.getParameter("hid"));
        Result result = null;
        HeadlineDetailVo headline = newsHeadlineService.findHeadlineDetail(hid);
        Map<String, Object> headlineMap = new HashMap<>();
        headlineMap.put("headline", headline);
        result = Result.ok(headlineMap);
        WEBUtil.writeJson(resp, result);
    }

}

(五)头条的修改和删除

对新闻进行操作前查看登录信息是否有效

1.登录校验

客户端

发送请求: uri:user/checkLogin

请求方式:

        GET

请求头:

        token

请求体:

       无

响应示例

  • 登录未过期

{
    "code":"200",
    "message":"success",
    "data":{}
}
  • 登录已过期

{
    "code":"504",
    "message":"loginExpired",
    "data":{}
}

  后端


@WebServlet("/user/*")
public class NewsUserControl extends BaseController {
        protected void checkLogin(HttpServletRequest req, HttpServletResponse resp) {
        //注意 请求参数 getParameter
        //请求头 getHeader
        String token = req.getHeader("token");
        Result result = null;
        if(!JwtHelper.isExpiration(token)){ //token未过期
            result = Result.ok(null);
        }else{
            result = Result.build(null,ResultCodeEnum.NOTLOGIN);
        }
        WEBUtil.writeJson(resp,result);

    }

}

2.提交头条发布

客户端

发送请求: uri:headline/publish

请求方式:

        POST

请求头:

        token

请求体:

       JSON

响应示例

  • 发布成功

{
    "code":"200",
    "message":"success",
    "data":{}
}
  • 失去登录状态发布失败

{
    "code":"504",
    "message":"loginExpired",
    "data":{}
}

  后端


@WebServlet("/headline/*")
public class NewsHeadlineControl extends BaseController {
    private NewsHeadlineService headlineService = new NewsHeadlineServiceImpl();
    protected void publish(HttpServletRequest req, HttpServletResponse resp) {
        String token = req.getHeader("token");
        //通过token获取用户id
        Long userId = JwtHelper.getUserId(token);
        HeadlineDetailVo headlineDetailVo = WEBUtil.readJson(req, HeadlineDetailVo.class);
        headlineDetailVo.setPublisher(userId.intValue());
        //将新闻信息存入数据库
        headlineService.addNewsHeadline(headlineDetailVo);
        WEBUtil.writeJson(resp,Result.ok(null));

    }


}

3.修改头条回显

点击修改头条时,显示原来内容

客户端

发送请求: uri:headline/findHeadlineByHid

请求方式:

        POST

请求头:

       无

请求体:

       键值对

响应示例

  • 查询成功

{
    "code":"200",
    "message":"success",
    "data":{
        "headline":{
            "hid":"1",
            "title":"马斯克宣布",
            "article":"... ... ",
            "type":"2"
        }
    }
}

  后端


@WebServlet("/headline/*")
public class NewsHeadlineControl extends BaseController {
    private NewsHeadlineService headlineService = new NewsHeadlineServiceImpl();
    protected void findHeadlineByHid(HttpServletRequest req, HttpServletResponse resp) {
        Integer hid = Integer.parseInt(req.getParameter("hid"));
        //通过新闻id获取对应新闻内容
        HeadlineDetailVo headlineDetailVo = headlineService.getByHid(hid);
        Map<String, Object> headlineMap = new HashMap<>();
        headlineMap.put("headline", headlineDetailVo);
        WEBUtil.writeJson(resp,Result.ok(headlineMap));

    }

}

4.保存修改

客户端

发送请求: uri:headline/update

请求方式:

        POST

请求头:

       无

请求体:

       键值对

响应示例

  • 修改成功

{
    "code":"200",
    "message":"success",
    "data":{}
}
  • 修改失败

{
    "code":"504",
    "message":"loginExpired",
    "data":{}
}

  后端


@WebServlet("/headline/*")
public class NewsHeadlineControl extends BaseController {
    private NewsHeadlineService headlineService = new NewsHeadlineServiceImpl();
    protected void update(HttpServletRequest req, HttpServletResponse resp) {
        HeadlineDetailVo headlineDetailVo = WEBUtil.readJson(req,HeadlineDetailVo.class);
        //将新闻修改内容更新到数据库
        headlineService.updateHeadline(headlineDetailVo);
        WEBUtil.writeJson(resp,Result.ok(null));


    }

}

5.删除头条

 客户端

发送请求: uri:headline/removeByHid

请求方式:

        POST

请求头:

       无

请求体:

       键值对

响应示例

  • 删除成功

{
    "code":"200",
    "message":"success",
    "data":{}
}
  • 删除失败

{
    "code":"504",
    "message":"loginExpired",
    "data":{}
    
}

  后端


@WebServlet("/headline/*")
public class NewsHeadlineControl extends BaseController {
    private NewsHeadlineService headlineService = new NewsHeadlineServiceImpl();
    protected void removeByHid(HttpServletRequest req, HttpServletResponse resp) {
        Integer hid = Integer.parseInt(req.getParameter("hid"));
        headlineService.removeByHid(hid);
        WEBUtil.writeJson(resp,Result.ok(null));
    }

}

六.案例中遇到的问题

  • tomcat输出日志乱码问题

    查看idea或cmd编码格式,到tomcat目录下,找到conf目录下的logging.properties,修改对应编码格式即可

  • 请求参数读取出错

    json数据错误使用getParameter()读取

    • 应使用ObjectMapper方法读取

    请求头数据错误使用getParameter()读取

    • 应使用getHeader()方法读取

  • 访问路径出错

    @WebServlet("/headline"),导致headline路径下方法不能被获得请求

    • 应修改为@WebServlet("/headline/*")

  • 数据库操作失误

    数据库采用下划线分割命名,而java中采用驼峰式命名

    • 访问时需要注意起别名,变量应转换为与java一致

    操作数据库时注意sql语句空格、变量顺序、数据类型等问题

其他的,就想不起来了...... 

本文侧重前后端统一接口的交互,其余代码没放出来,需要自取,菜鸡一枚,有错误和不足的地方还望指出。

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值