黑马程序员Javaweb重点笔记(一)(2023年版)


前言

我个人有一个学习习惯就是把学过的内容整理出来一份重点笔记,笔记往往只会包括我认为比较重要的部分或者容易忘记的部分,以便于我快速复习,如果有错误欢迎大家批评指正。
另外:本篇笔记大部分参考了JavaWeb这个专栏的文章,相当于是这个专栏的压缩版,特此鸣谢作者「_Matthew」
版权声明:本文为CSDN博主「_Matthew」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_46225503/article/details/130778031


黑马程序员Javaweb重点笔记

web前端开发

万维网也就是(w3c)主要由三个部分组成:

HTML:负责网页的结构(页面元素和内容)

CSS:负责网页的表现(网页元素的外观、位置等页面样式,如:颜色、大小)

JavaScript:负责网页的行为(交互效果)

Maven

依赖就是jar包,jar包就是依赖

通常会创建一个Maven模块作为项目的父工程,只需要所以可以把src目录直接删除,这样的话,其他的只需要继承父工程就可以了,避免了很多重复的依赖

下面是在子工程中继承父工程:

<parent>
	<artifactId>maven-demo-parent</artifactId>
	<groupId>net.javatv.maven</groupId>
	<version>1.0-SNAPSHOT</version>
</parent>

在父工程中还可以使用dependencyManagement标签对依赖管理,经典使用就是想要更新这个项目中依赖的版本的时候不用去各个模块的pom文件中去更改版本,子工程也就不需要指定版本号,直接在父工程的pom文件中修改

对同一框架的一组jar包最好使用相同的版本,为了方便升级框架,可以将jar包的版本信息统一提取出来,统一声明版本号:

<!-- 通过自定义属性,统一指定Spring的版本 -->
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- 自定义标签,维护Spring版本数据 -->
    <spring.version>5.3.19</spring.version>
</properties>

在需要的地方使用${}

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>net.javatv.maven</groupId>
    <artifactId>maven-demo-parent</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <modules>
        <module>demo-module</module>
    </modules>


    <!-- 通过自定义属性,统一指定Spring的版本 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <!-- 自定义标签,维护Spring版本数据 -->
        <spring.version>5.3.19</spring.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>${spring.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

Maven中可以使用聚合的方式来快速的构建项目,如果不聚合,很多时候都需要各个项目一个个打包,在实际开发当中一般都是聚合和继承一起使用

聚合只需要在父模块的pom文件中通过modules下的module子元素来添加需要聚合的模块的目录路径,比如下面这个例子就是把uer-service聚合到父模块下,对父工程进行clean install的时候会发现,他会连着子工程一块进行构建

<modules>
	<module>user-service</module>
</modules>

Web入门

HTTP协议是无状态的协议:对于事务处理没有记忆能力。每次请求-响应都是独立的。缺点:多次请求间不能共享数据。优点:速度快

HTTP常见的响应状态码:

200:ok 客户端请求成功,即处理成功

404:Not Found 请求资源不存在,一般是URL输入有误,或者网站资源被删除了

500:Internal Server Error 服务器发生不可预期的错误。服务器异常,可以去查看日志来解决

Tomcat是一款开源免费的轻量级Web服务器,支持Servlet/JSP少量JavaEE规范。

请求

Postman是一款功能强大的网页调试与发送网页的HTTP请求的插件,可以在与前端联调之前进行Postman与后端的测试。

GET方式:具体的参数数据都会在链接中展示出来,比如:http://localhost:8080/simpleParam?name=Jack&age=12 这个请求当中就包含了两个参数,一个是name=Jack,一个是age=12,如果想要获取这两个参数,就要用下面这种方式

@RestController
public class RequestController
{
    @RequestMapping("/simpleParam")
    //注意这个方法中传入参数的参数名应该和链接中参数的名字一样,正如这里的name和age
    public String simpleParam(String name,int age)
    {
        
        System.out.println("name="+name);
        System.out.println("age ="+age);
        return "OK";
    }
}

如果说方法形参名称与请求参数名称不匹配,可以使用@RequestParam完成映射,例如刚才的代码可以改写成

@RestController
public class RequestController
{
    @RequestMapping("/simpleParam")
    public String simpleParam(@RequestParam(name="name")String username,int age)
    {
        
        System.out.println("name="+name);
        System.out.println("age ="+age);
        return "OK";
    }
}

Post方式:关键信息不会在链接中显示,会在body中定义

如果我们要传递许多个参数,原来这种方式不是很方便,所以可以直接传入一个实体对象。提前定义一个实体对象,其中的成员变量都是要与传入的参数是对应的,例如下面用User类来接收

User类

package com.example.springbootwebre4sp.pojo;

public class User {
    private String name;
    public  Integer age;

    public User() {
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

RequestController

package com.example.springbootwebre4sp.controller;

import com.example.springbootwebre4sp.pojo.User;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RequestController
{
    //原始方式
    @RequestMapping("/simpleParam")
    public String simpleParam(String name,int age)
    {

        System.out.println("name="+name);
        System.out.println("age ="+age);
        return "OK";
    }
    //现在的方式
    @RequestMapping("/simplePojo")
    public String simplePojo(User user){
        System.out.println(user);
        return "OK";
    }
}

复杂对象只需要传入key的时候按照对应的属性传入就行了,比如说你有一个这样的类

public class User{
	private String name;
	private Integer age;
	private Address address;
}

其中Address的属性是这样的

public class Address{
	private String province;
	private String city;
}

发送过来请求的body中应该有这样的key,address.province和address.city,这样就能直接对应上了,再用下面这种形式就是没有问题的

@RequestMapping("/simplePojo")
public String simplePojo(User user){
    System.out.println(user);
    return "OK";
}

数组集合参数:

数组:请求数组名与形参中数组变量名相同,可以直接使用数组封装

集合:请求参数名与形参集合变量名相同,通过@RequestParam绑定参数关系,例如下面这样

@RestController
public class RequestController
{
    @RequestMapping("/listParam")
    public String listParam(@RequestParam List<String> hobby)
    {
        System.out.println(hobby);
        return "OK";
    }
}

日期参数:

入职时间、生日等时间类型的表单可以封装到LocalDateTime中,但是由于前端传入的时间类型有很多种格式,所以可以用@DateTimeFormat来声明日期格式,正如下面的代码

@RestController
public class RequestController
{
    @RequestMapping("/dataParam")
    public String dataParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime)
    {
        System.out.println(updateTime);
        return "OK";
    }
}

JSON参数:JSON数据键名与形参对象的属性名相同,需要使用@RequestBody标识

@RestController
public class RequestController
{
    @RequestMapping("/jsonParam")
    public String jsonParam(@RequestBody User user)
    {
        System.out.println(user);
        return "OK";
    }
}

路径参数:通过URL直接传递参数,使用{…}来标识该路径参数,需要使用@PathVariable获取路径参数,例如:http://localhost:8080/path/1。因为还有可能有path/2,path/3等等,所以不能直接通过@RequestMapping(“/path/1”)这种方式来直接获取参数,所以要用到@PathVariable获取路径参数,下面为示例:

@RestController
public class RequestController
{
    //原始方式
    @RequestMapping("/path/{id}")
    public String pathParam(@PathVariable Integer id)
    {
        System.out.println(id);
        return "OK";
    }
}

响应

@ResponseBody将方法返回值直接响应,如果返回值类型是实体对象/集合,将会转换成JSON格式响应。

因为@RestController=@Controller+@ResponseBody,所以直接在Controller上只需要加@RestController就可以了

因为前端需要后端返回的数据,所以如果要是每次返回的类型都是不一样的,前端处理起来是比较麻烦的。因此一般采用的方法是定义一个Result类来统一返回类型:

Result

public class Result {
    private Integer code ;//1 成功,0失败
    private String msg; //提示信息
    private Object data; // 数据date


    public Result() {
    }

    public Result(Integer code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    /**
     * 获取
     * @return code
     */
    public Integer getCode() {
        return code;
    }

    /**
     * 设置
     * @param code
     */
    public void setCode(Integer code) {
        this.code = code;
    }

    /**
     * 获取
     * @return msg
     */
    public String getMsg() {
        return msg;
    }

    /**
     * 设置
     * @param msg
     */
    public void setMsg(String msg) {
        this.msg = msg;
    }

    /**
     * 获取
     * @return data
     */
    public Object getData() {
        return data;
    }

    /**
     * 设置
     * @param data
     */
    public void setData(Object data) {
        this.data = data;
    }

    public String toString() {
        return "Result{code = " + code + ", msg = " + msg + ", data = " + data + "}";
    }
    public static Result success (Object data) {
        return new Result( 1,"sucess", data) ;
    }
    public static Result ssucces() {
        return new Result(1,"sucess",null) ;
    }
    public static Result error (String msg) {
        return new Result( 0,msg,null) ;
    }

}

在Result中给了三种构造方式,用来面对三种情况:成功并且需要给前端返回数据、成功但是不需要给前端返回数据、失败

Result的三种构造方式

public static Result success (Object data) {
	return new Result( 1,"sucess", data) ;
}
public static Result ssucces() {
	return new Result(1,"sucess",null) ;
}
public static Result error (String msg) {
	return new Result( 0,msg,null) ;
}

分层解耦

把数据访问、逻辑处理、与数据库交互等过程都放在一个类中是比较难以维护的,采用分层的方式编写代码最好,各司其职,维护起来比较方便。

一般都是三层架构:

controller层:控制层,接受前端发送的请求,对请求进行处理,并响应数据

service层:业务逻辑层,处理具体的业务逻辑

dao层:数据访问层,负责数据访问操作,包括数据的增、删、改、查

下面展示原始的三层架构方式,后面加入IOC之后会更加的简单,所以下面这种方式理解了就可以,不需要记下来怎么操作,我以横线划分这一块区域


下面是IDEA中目录结构
在这里插入图片描述

EmpController

package com.example.springbootwebre4sp.controller;

import com.example.springbootwebre4sp.dao.impl.EmpDaoA;
import com.example.springbootwebre4sp.pojo.Emp;
import com.example.springbootwebre4sp.pojo.Result;
import com.example.springbootwebre4sp.service.EmpService;
import com.example.springbootwebre4sp.service.impl.EmpServiceA;
import com.example.springbootwebre4sp.utils.XmlParserUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class EmpController {
    private EmpService empService = new EmpServiceA();

    @RequestMapping("/listEmp")
    public Result list(){
        List<Emp> empList = empService.listEmp();

        //3. 响应数据
        return Result.success(empList);
    }

}

在这里插入图片描述

package com.example.springbootwebre4sp.dao.impl;

import com.example.springbootwebre4sp.dao.EmpDao;
import com.example.springbootwebre4sp.pojo.Emp;
import com.example.springbootwebre4sp.utils.XmlParserUtils;

import java.util.List;

public class EmpDaoA implements EmpDao {
    @Override
    public List<Emp> listEmp() {
        String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
        System.out.println(file);
        List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
        return empList;
    }
}


在这里插入图片描述

package com.example.springbootwebre4sp.dao;

import com.example.springbootwebre4sp.pojo.Emp;

import java.util.List;

public interface EmpDao {
    //获取列表数据
    public List<Emp> listEmp();

}


在这里插入图片描述

package com.example.springbootwebre4sp.service.impl;

import com.example.springbootwebre4sp.dao.EmpDao;
import com.example.springbootwebre4sp.dao.impl.EmpDaoA;
import com.example.springbootwebre4sp.pojo.Emp;
import com.example.springbootwebre4sp.service.EmpService;

import java.util.List;

public class EmpServiceA implements EmpService {
    private EmpDao empDao = new EmpDaoA();

    @Override
    public List<Emp> listEmp() {
        List<Emp> empList = empDao.listEmp();
        empList.stream().forEach(emp -> {
            //处理 gender 1: 男, 2: 女
            String gender = emp.getGender();
            if("1".equals(gender)){
                emp.setGender("男");
            }else if("2".equals(gender)){
                emp.setGender("女");
            }

            //处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
            String job = emp.getJob();
            if("1".equals(job)){
                emp.setJob("讲师");
            }else if("2".equals(job)){
                emp.setJob("班主任");
            }else if("3".equals(job)){
                emp.setJob("就业指导");
            }
        });
        return empList;
    }
}


在这里插入图片描述

package com.example.springbootwebre4sp.service;

import com.example.springbootwebre4sp.pojo.Emp;

import java.util.List;

public interface EmpService {
    //获取员工列表数据
    public List<Emp> listEmp();


}



分层解耦(IOC-DI)

内聚:软件中各个功能模块内部的功能联系
耦合:衡量软件中各个层/模块之间的依赖、关联的程度
设计软件的原则:高内聚低耦合

下面这两个概念是框架比较重要的一部分内容,想要深度学习其中的原理可以搜索一下相关的博客,有些博客讲的很好。
IOC(Inversion of Control,控制反转) 是一种设计模式,它将对象之间的依赖关系的控制权从程序代码中转移到了容器中,通过容器来实现对象的创建、销毁、管理和依赖注入等操作,从而降低代码的耦合度,提高代码的可维护性和代码的可扩展性。
DI(Dependency Injection,依赖注入)是指在创建对象的时候,将对象所依赖的其他对象的引用作为参数传递给对象的构造函数或者其他方法中,从而实现对象之间的依赖关系。这样,对象之间的依赖关系就不再由程序代码直接控制,而是由容器来管理。这样可以使程序代码更加灵活、易于维护和扩展。

IOC三种配置方式:XML配置、Java配置、注解配置(课程中主要用到的方式)
依赖注入的三种方式:构造函数注入、Setter方法注入、注解注入(课程中主要用到的方式)
在这里插入图片描述
从上图中可以看出需要在Service层以及Dao层的实现类上加@Component,在Controller以及Service注入运行时前面加上@Autowired,也就是原来是这个样子:

private EmpService empService = new EmpService();

现在变成了这个样子:

@Autowired
private EmpService empService;

简单讲原理就是:
@Component:将当前类交给IOC容器管理,成为IOC容器中的bean
@Autowired:运行时,IOC容器会提供该类型的bean对象,并赋值给该变量

Bean的声明:
要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一:
@Component 声明bean的基础注解 不属于以下三类时,用此注解
@Controller 是@Component的衍生注解 标注在控制器类上
@Service 是@Component的衍生注解 标注在业务类上
@Repository 是@Component的衍生注解 标注在数据访问类上(由于与mybatis整合,用的少)
推荐:下面的三类分别标注Controller,Service,DAO三层的bean对象
工具类常常想要利用容器,用Component。
注意事项:
声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
使用以上四个注解都可以声明bean,但是在springboot集成web开发中,声明控制器bean只能用@Controller

前面声明bean的四大注解,想要生效,还需要被组件扫描注解@ComponentScan扫描,但是在上文提到的代码中并没有使用这个注解,这是因为启动类声明注解@SpringBootApplication 中包含了这个注解,默认扫描的范围是启动类所在包及其子包

@Autowired注解,默认是按照类型进行,如果存在多个相同类型的bean,则会报错,解决方式是下面三个注解(遇到问题的时候再去了解使用方式就行):@Primary、@Qualifier、@Resource

MySQL

DDL语言:用来定义数据库对象(数据库,表,字段),这一部分一般都用图形化界面代替了,所以不用专门记操作的语句,但是要会设计表。

数值类型:
在这里插入图片描述
数值中使用比较多的是:TINIINT,INT,DOUBLE,DECIMAL

字符串类型:
在这里插入图片描述
在字符串类型当中要重点注意一下char和varchar的区别
比如:char(10)与varchar(10)的区别?
1、当年存储1个字节的时候,使用char还是会使用10个字节的空间。而varchar可以只用1个空间
2、但是char的性能更高,因为不需要每次根据内容计算空间

时间类型:
在这里插入图片描述

DML语言(Data Manipulation Language):数据操作语言,用来对数据库中表的数据记录进行增删改操作,这个部分是重点,需要熟练使用
1、给指定字段添加数据:INSERT INTO 表名(字段1,字段2...) VALUES(值1,值2...)
2、给全部字段添加数据:INSERT INTO 表名 VALUES(值1,值2...)
3、批量添加数据:INSERT INTO 表名 (字段名1,字段名2,...) VALUES (值1,值2...),(值1,值2...),(值1,值2...);
INSERT INTO 表名 VALUES (值1,值2...),(值1,值2...),(值1,值2...);
注意事项:

  • 插入数据时,指定的字段顺序需要与值的顺序一一对应
  • 字符串和日期型数据应该包含在引号中
  • 插入的数据大小,应该在字段的规定范围内

4、修改数据:UPDATE 表名 SET 字段名1=值1,字段名2=值2...[WHERE条件]
注意:修改语句的条件可以有,也可以没有,如果没有条件,则会修改整张表的所有数据

5、删除数据:DELETE FROM 表名 [WHERE条件]
注意:

  • DELETE语句的条件可以有,也可以没有,如果没有条件,则会删除整张表的所有数据
  • DELETE语句不能删除某一个字段的值(可以使用UPDATE)

DQL语言(Data Query Language):数据查询语言,用来查询数据库中表的记录,这一部分内容也非常重要
查询关键字:SELECT

SELECT
	字段列表
FROM
	表名列表
WHERE
	条件列表
GROUP BY
	分组字段列表
HAVING
	分组后条件列表
ORDER BY
	排序字段列表
LIMIT
	分页参数
  • 基本查询
  • 条件查询(WHERE)
  • 聚合函数(count、max、min、avg、sum)
  • 分组查询(GROUP BY)
  • 排序查询(ORDER BY)
  • 分页查询(LIMIT)

基础查询:
查询多个字段:SELECT 字段1,字段2,字段3 FROM 表名;
查询所有字段:SELECT * FROM 表名;
设置别名:SELECT 字段1 [AS别名1],字段2 [AS别名2]... FROM 表名
去除重复记录:SELECT DISTINCT 字段列表 FROM 表名;

条件查询:SELECT 字段列表 FROM 表名 WHERE 条件列表;

聚合函数:将一列数据作为一个整体,进行纵向计算。
SELECT 聚合函数(字段列表) FROM 表名;
例如:select avg(age) from emp;

分组查询:
SELECT 字段列表 FROM 表名 [WHERE条件] GROUP BY 分组字段名 [HAVING分组后过滤条件]
where与having区别:
执行的时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。
判断条件不同:where不能对聚合函数进行判断,而having可以
下面的几个例子可以认真看一下:

-- 分组查询-------------------------------------------
-- 1.根据性别分组,统计男性员工和女性员工的数量
select gender,count(*) from emp group by gender ;

-- 2.根据性别分组,统计男性员工和女性员工的平均年龄
select gender,avg(age) from emp group by gender ;

-- 3.查询年龄小于45的员工,并根据工作地址分组,获取员工数量大于等于3的工作地址
select  workaddress,count(*) from emp where age<45 group by workaddress having count(*)>3;

注意:
执行顺序:where >聚合函数 >having
分组之后查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义

排序查询:
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1 , 字段2 排序方式2;
排序方式:
ASC:升序(默认方式)
DESC:降序
如果是多个字段排序,当第一个字段相同时,才会根据第二个字段进行排序,看一下下面的案例就明白了:

-- 排序查询-------------------------------------------
-- 1.根据年龄对公司的员工进行升序排序
select * from emp order by  age ASC;

-- 2.根据入职时间,对员工进行降序排序
select * from emp order by  entrydate DESC ;

-- 3.根据年龄对公司的员工进行升序排序,年龄相同,再按照入职时间进行降序排序
select * from emp order by  age ASC ,entrydate DESC ;

分页查询:
SELECT 字段列表 FROM 表名 LIMIT 起始索引,查询记录数;
注意:
起始索引从0开始,起始索引=(查询页码-1)✖每页显示记录数
分页查询在不同的数据库中有不同的实现,MySQL中是LIMIT
如果查询的是第一页数据,起始索引可以省略

-- 分页查询
-- 1.查询第1页员工数据,每页展示10条记录
select * from  emp limit 0,10;
select * from  emp limit 10;
-- 2.查询第2页员工数据,每页展示10条记录
select * from  emp limit 10,10;

上面关于MySQL这些都是一些较为基础的知识点,有许多更加复杂的知识点可以深入学习一下,比如多表查询,在实际开发中运用的很多,我个人是计划在下一步做Javaweb项目练手的时候再结合案例深入学习一下

  • 24
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值