社交网站后端项目开发日记(一) 1. Spring相关知识 2. SpringMVC相关 3. MyBatis 4. 总结

本项目目标是开发一个社区网站,拥有发帖、讨论、搜索、登录等一个正常社区拥有的功能。涉及到的版本参数为:

  • JDK1.8
  • Maven3.8.1(直接集成到IDEA)
  • Springboot 2.5.1
  • tomcat

参考网站(在使用框架过程中可能会看的开发文档):

https://mvnrepository.com/ 查找maven依赖

https://mybatis.org/mybatis-3/zh/index.html mybatis的官方文档,配置等都有说明

项目代码已发布到github https://github.com/GaoYuan-1/web-project

关于数据库文件,该篇博客中已有提到,可去文中github获取数据 MySQL基础篇(一)

本文第一篇只介绍了基础,在(二)中将会介绍如何实现登录界面等后续内容。最终将会把完整项目经历发布出来。

本系列主要介绍的是实战内容,对于理论知识介绍较少,适合有一定基础的人。

首先创建一个项目,可利用Spring Initializr

本人配置如下:

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

maven项目的 pom.xml 中初始依赖如下,后面会增加更多依赖。

 
<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>

   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>runtime</scope>
      <optional>true</optional>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
   </dependency>
</dependencies>

记录一些基本概念,Spring的知识可能说的比较少,本篇关注于如何对网站进行实现。

Spring Bean是被实例的,组装的及被Spring 容器管理的Java对象。

Spring 容器会自动完成@bean对象的实例化。

创建应用对象之间的协作关系的行为称为:装配(wiring),这就是依赖注入的本质。

在使用 Spring Initializr 之后,第一个接触的注解为:

 
@SpringBootApplication

我们可以把 @SpringBootApplication 看作是 @Configuration@EnableAutoConfiguration@ComponentScan 注解的集合。

根据 SpringBoot 官网,这三个注解的作用分别是:

  • @EnableAutoConfiguration :启用 SpringBoot 的自动配置机制
  • @ComponentScan : 扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描该类所在的包下所有的类。
  • @Configuration :允许在 Spring 上下文中注册额外的 bean 或导入其他配置类(表示该类是配置类)

Spring通过识别一些注解可以让容器自动装填bean:

  • @Component :通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。
  • @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
  • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao (Data Access Object)层。
  • @Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。

关于@Scope,负责声明Bean的作用域:

 
@Scope("singleton")  //唯一 bean 实例,Spring 中的 bean 默认都是单例的。
@Scope("prototype")  //每次请求都会创建一个新的 bean 实例。
@Scope("request")    //每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
@Scope("session")    //每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。

关于@Autowired:

自动导入对象到类中,被注入进的类同样要被 Spring 容器管理。从构造器,到方法,到参数、属性、注解,都可以加上@Autowired注解。

2. SpringMVC相关

可以先了解一些HTTP流的相关知识:(参考自MDN Web Docs)

当客户端想要和服务端进行信息交互时(服务端是指最终服务器,或者是一个中间代理),过程表现为下面几步:

  1. 打开一个TCP连接:TCP连接被用来发送一条或多条请求,以及接受响应消息。客户端可能打开一条新的连接,或重用一个已经存在的连接,或者也可能开几个新的TCP连接连向服务端。

  2. 发送一个HTTP报文:HTTP报文(在HTTP/2之前)是语义可读的。在HTTP/2中,这些简单的消息被封装在了帧中,这使得报文不能被直接读取,但是原理仍是相同的。

     
    GET / HTTP/1.1
    Host: developer.mozilla.org
    Accept-Language: fr
    
  3. 读取服务端返回的报文信息:

     
    HTTP/1.1 200 OK
    Date: Sat, 09 Oct 2010 14:28:02 GMT
    Server: Apache
    Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT
    ETag: "51142bc1-7449-479b075b2891b"
    Accept-Ranges: bytes
    Content-Length: 29769
    Content-Type: text/html
    
    <!DOCTYPE html... (here comes the 29769 bytes of the requested web page)
    
  4. 关闭连接或者为后续请求重用连接。

当HTTP流水线启动时,后续请求都可以不用等待第一个请求的成功响应就被发送。然而HTTP流水线已被证明很难在现有的网络中实现,因为现有网络中有很多老旧的软件与现代版本的软件共存。因此,HTTP流水线已被在有多请求下表现得更稳健的HTTP/2的帧所取代。

HTTP请求的例子:

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

响应的例子:

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

2.1 SpringMVC概要

三层架构:表现层,业务层和数据访问层。

MVC:Model(模型层),View(视图层),Controller(控制层)

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

核心组件: DispatcherServlet

2.2 Thymeleaf思想

如果想给浏览器返回一个动态网页,则需要一个工具支持,例如:Thymeleaf(模板引擎,生成动态的HTML)。

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

该引擎需要学习的有:标准表达式,判断与循环,模板的布局。

学习建议参考官方文档 https://www.thymeleaf.org/index.html

2.3 SpringMVC代码示例

GET请求

@RequestMapping支持Servlet的request和response作为参数,以下为一个简单示例:

 
@Controller
@RequestMapping("/alpha")
public class AlphaController {
    @RequestMapping("/hello")
    @ResponseBody
    public String sayHello(){
        return "Hello Spring Boot.";
    }

    @RequestMapping("/http")
    public void http(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //获取请求数据
        System.out.println(request.getMethod());
        System.out.println(request.getServletPath());//请求路径
        Enumeration<String> enumeration = request.getHeaderNames();//得到请求行的key
        while(enumeration.hasMoreElements()) {
            String name = enumeration.nextElement(); //当前值(key)
            String value = request.getHeader(name);//得到value
            System.out.println(name + ":" + value);
        }
        System.out.println(request.getParameter("code"));

        // 返回响应数据
        response.setContentType("text/html;charset=utf-8");//返回网页类型的文本
        PrintWriter writer = response.getWriter();
        writer.write("<h1>牛客网</h1>");//这里只进行简单输出
        writer.close();
    }
}

在项目Controller层加入代码,以response体返回一个html的文本。

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

这是通过底层对象处理请求的方式,便于理解。

更简单的方式为:

 
// GET请求,用于获取某些数据
    // /students?current=1&limit=20 假设查询学生数据,第一页,每页20条
    @RequestMapping(path = "/students", method = RequestMethod.GET)
    @ResponseBody
//    public String getStudents(int current,int limit) { //直接使用Int类型,前端控制器会自动识别匹配
//        System.out.println(current);
//        System.out.println(limit);
//        return "some students";
//    }
//    也可加上注解
    public String getStudents(
            @RequestParam(name = "current", required = false, defaultValue = "1") int current,
            @RequestParam(name = "limit", required = false, defaultValue = "1")  int limit) {
        System.out.println(current);
        System.out.println(limit);
        return "some students";
    }

利用@ResponseBody注解,实现效果为:

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

控制台返回结果:

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

利用这种方式,不论是返回数据还是获取数据都很方便。

另外,通过路径方式传参查询的话:(注意,路径长度并不是无限的,并不可以传很多参数)

 
// /student/123  查询某个学生,直接放在路径中
@RequestMapping(path = "/student/{id}", method = RequestMethod.GET)
@ResponseBody
public String getStudent(@PathVariable("id") int id) {
    System.out.println(id);
    return "a student";
}

注意以上传参时使用的两个注解。

POST请求

如何向浏览器提交数据?

在项目静态文件中添加html文件,action指示路径

 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>增加学生</title>
</head>
<body>

    <form method="post" action="/community/alpha/student">
        <p>
            姓名:<input type="text" name="name">
        </p>
        <p>
            年龄:<input type="text" name="age">
        </p>
        <p>
            <input type="submit" value="保存">
        </p>
    </form>

</body>
</html>
 
//POST请求
@RequestMapping(path = "/student", method = RequestMethod.POST)
@ResponseBody
public String saveStudent(String name, int age) {
    System.out.println(name);
    System.out.println(age);
    return "success";
}

在Controller中代码如下,展示效果:

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

控制台:

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

响应HTML数据

从程序内部响应到HTML

 
//响应HTML数据
@RequestMapping(path = "/teacher", method = RequestMethod.GET)
public ModelAndView getTeacher() {   //这个对象就是向前端控制器返回的moder和view
    ModelAndView mav = new ModelAndView();
    mav.addObject("name", "张三");
    mav.addObject("age", 30);
    mav.setViewName("/demo/view");//这个view实际上指的是view.html
    return mav;
}

Controller代码

此外,还需要一个动态网页,利用thymeleaf模板引擎(resource/templates)。

 
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"> <!--声明这不是html文件,而是一个thymeleaf模板-->
<head>
    <meta charset="UTF-8">
    <title>Teacher</title>
</head>
<body>
    <p th:text="${name}"></p>
    <p th:text="${age}"></p>
</body>
</html>

实现效果,程序已经设定初始值。

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

模板引擎会自动进行处理。

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

另一种方式:

 
@RequestMapping(path = "/school", method = RequestMethod.GET)
public String getSchool(Model model) {    //前端控制器会创建一个model
    model.addAttribute("name","大学");
    model.addAttribute("age",80);
    return "/demo/view";  //这里return的是view的路径
}

这两种方式是model和view的对象使用方式不同。效果还是一致的,第二种要更加简便一些。

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

响应JSON数据

异步请求可以理解为:当前网页不刷新,但是进行了数据交互,比如注册账号时,经常会检测用户名是否重复,这时候网页并没有刷新,但是访问了数据库进行查询。

 
//响应JSON数据(异步请求)
// Java对象传给浏览器:需要转为JS对象,这时候就可以通过JSON进行转化
// Java对象-> JSON字符串 -> JS对象等等
@RequestMapping(path = "/emp", method = RequestMethod.GET)
@ResponseBody
public Map<String,Object> getEmp() {  //自动会将map转为JSON字符串
    Map<String,Object> emp = new HashMap<>();
    emp.put("name","张三");
    emp.put("age",23);
    emp.put("salary",8000.00);
    return emp;
}

注意,这里并没有返回html。

这里只是简单介绍了响应方式,以后的博客中会介绍具体应用及代码。

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

3. MyBatis

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结

mybatis文档

mybatis-spring文档

在maven项目pom.xml中添加依赖

 
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>8.0.25</version>
</dependency>
<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>2.2.0</version>
</dependency>

在SpringBoot框架下,只需要对application.properties进行配置,增加如下:

 
# DataSourceProperties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/community?characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong
spring.datasource.username=root
spring.datasource.password=Ss6215615
#设置连接池,这个比较好
spring.datasource.type=com.zaxxer.hikari.HikariDataSource 
spring.datasource.hikari.maximum-pool-size=15
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=30000

# MybatisProperties
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.nowcoder.community.entity
mybatis.configuration.useGeneratedKeys=true
#自动匹配 a_b == aB
mybatis.configuration.mapUnderscoreToCamelCase=true

# logger,设置日志,方便在控制台查看信息
logging.level.com.nowcoder.community=debug

mybatis.type-aliases-package=com.nowcoder.community.entity

这行代码声明了SQL中记录在Java中的对象位置,根据SQL中的属性建立对象。

 
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;
    //等等,还有set,get,toString

建立对象之后,在项目中的dao文件,建立UserMapper(对于User的操作)接口,Mybatis只需要通过xml文件对操作进行声明。

 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nowcoder.community.dao.UserMapper">  <!-- 这里写UserMapper的全限定名 -->

    <sql id="selectFields">
        id, username, password, salt, email, type, status, activation_code, header_url, create_time
    </sql>

    <sql id="insertFields">
        username, password, salt, email, type, status, activation_code, header_url, create_time
    </sql>

    <select id="selectById" resultType="User">  <!-- 配置里进行过设置package,否则需要写全限定名 -->
        select <include refid="selectFields"></include>
        from user
        where id = #{id}  <!-- 这里的意思是要引用方法的参数 -->
    </select>

    <select id="selectByName" resultType="User">  <!-- 配置里进行过设置package,否则需要写全限定名 -->
        select <include refid="selectFields"></include>
        from user
        where username = #{username}  <!-- 这里的意思是要引用方法的参数 -->
    </select>

    <select id="selectByEmail" resultType="User">  <!-- 配置里进行过设置package,否则需要写全限定名 -->
        select id, username, password, salt, email, type, status, activation_code, header_url, create_time
        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>

这里建立了增删改的操作。

 
mybatis.mapper-locations=classpath:mapper/*.xml

根据已有的配置在resource文件夹中建立mapper目录和.xml文件。

由于.xml文件不会自动检测编译,建议在test中依次测试相应功能,以免出现错误。

4. 总结

本项目计划使用SpringBoot框架进行一个社交网站的开发,首先使用Spring Initializr对maven项目进行建立,之后对Spring的基本概念进行了一定阐述,IOC和AOP均没有讲到,将会在后续开放的Spring学习篇中,对SpringMVC的基本使用(GET,POST请求和响应数据)进行了代码示范,方便理解后续代码。另外,介绍了Mybatis的使用,以及公布了部分示范代码。

上手起来是非常快的,本系列的目的在于,重点讲解实战部分,理论部分将在其他博客中展开。

下篇博客将会对网站的登陆界面等如何实现进行阐述。

 

__EOF__

 
社交网站后端项目开发日记(一)
1. Spring相关知识
2. SpringMVC相关
3. MyBatis
4. 总结
  • 本文作者: GaoYuan206
  • 本文链接: https://www.cnblogs.com/gaoyuan206/p/15013659.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐】一下。