JavaWeb考察点

JavaWeb考点:

1. HTTP协议

  1. 概念:

    • HTTP:Hyper Text Transfer Protocol(超文本传输协议),规定了浏览器与服务器之间数据传输的规则。HTTP协议是无状态协议: 对于数据没有记忆能力。每次请求-响应都是独立的,不会记录任何信息。
  2. 基于两个点实现:

    • 基于TCP协议: 面向连接,安全

    • 基于请求-响应模型: 请求和响应是一一对应关系,没有请求,就没有响应,一次请求对应一次响应(先请求后响应)

  3. 优缺点:

    • 优点: 速度快

    • 缺点: 多次请求间不能共享数据

无法共享数据可以使用会话技术(Cookie、Session)来解决这个问题。

2. spring中请求参数接收

  1. 简单参数:
    • springboot参数名一致(原始方式使用极少)
      • 原始方式:通过Servlet中提供的API:HttpServletRequest(请求对象),获取请求的相关信息。通过HttpServletRequest的对象request.getParameter(“请求参数名”)
      • 请求参数名与形参变量名相同,定义同名的形参即可接收参数。
    • springboot参数名不一致
      • 通过@RequestParam注解完成映射 url请求参数名:name @RequestParam("name") String username
  2. 实体参数:(简单实体对象)
    • 请求参数名与实体类的属性名相同:
      • 参数名和实体类属性名一致时正常赋值
    • 参数名和实体类属性名不一致时:
      • 赋值为null
    • 复杂实体对象的封装,需要遵守如下规则:
      • 请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套实体类属性参数。通过对象名.属性名的方式
  3. 数组集合参数:
    • 数组参数:
      • 请求参数名与形参数组名称相同且请求参数为多个,定义数组类型形参即可接收参数。
      • 前端请求时,有两种传递形式:?hobby=game&hobby=java or ?hobby=game,java
    • 集合参数:
      • 请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam 绑定参数关系。
      • 默认情况下,请求中参数名相同的多个值,是封装到数组。如果要封装到集合,要使用@RequestParam绑定参数关系
      • 两种传递形式:?hobby=game&hobby=java or ?hobby=game,java
  4. 日期参数:
    • 参数名和形参变量名保持一致,变量名通过@DateTimeFormat注解,以及其pattern属性来设置日期的格式。
    • 格式:@DateTimeFormat(pattern = “yyyy-MM-dd HH:mm:ss”) LocalDateTime updateTime
  5. JSON参数:
    • 服务端Controller方法接收JSON格式数据:
      • 传递json格式的参数,在Controller中会使用实体类进行封装。
      • 封装规则:JSON数据键名与形参对象属性名相同,定义POJO类型形参即可接收参数。需要使用 @RequestBody标识。
      • @RequestBody注解:将JSON数据映射到形参的实体类对象中(JSON中的key和实体类中的属性名保持一致)
  6. 路径参数:
    • 前端:通过请求URL直接传递参数
    • 后端:使用{…}来标识该路径参数,需要使用@PathVariable获取路径参数
    • @RequestMapping(“/path/{id}/{name}”) —> @PathVariable Integer id, @PathVariable String name

3. sql语句:聚合函数,分组,排序,分页,模糊查询…

select  字段列表  
from   表名   
[where  条件列表] 
[group by  分组字段 ] 
order  by  字段1  排序方式1 , 字段2  排序方式2;

注意事项:

分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义

执行顺序:where > 聚合函数 > having

where与having区别(面试题)

执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。
判断条件不同:where不能对聚合函数进行判断,而having可以。

4. mybatis参数占位符,动态sql标签

占位符:在Mybatis中提供的参数占位符有两种:${…} 、#{…}

  • #{…}

    • 执行SQL时,会将#{…}替换为?,生成预编译SQL,会自动设置参数值。参数值中的特殊符号会被转义

    • #例子
      select * from emp where username='abc' and password='\' or \'1\' = \'1' 
      
    • 使用时机:参数传递,都使用#{…}

  • ${…}

    • 拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入问题

    • 使用时机:如果对表名、列表进行动态设置时使用

    • 注意事项:在项目开发中,建议使用#{…},生成预编译SQL,防止SQL注入安全。

动态sql标签

  1. <if>:用于判断条件是否成立。使用test属性进行条件判断,如果条件为true,则拼接SQL。

    • <if test="条件表达式">
      要拼接的sql语句
      </if>
      
  2. <where>只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或OR

  3. <set>:动态的在SQL语句中插入set关键字,并会删掉额外的逗号。(用于update语句中)

  4. 使用<foreach>遍历deleteByIds方法中传递的参数ids集合

    • <foreach collection="集合名称" item="集合遍历出来的元素/项" separator="每一次遍历使用的分隔符" 
               open="遍历开始前拼接的片段" close="遍历结束后拼接的片段">
      </foreach>
      
      
  5. 可以对重复的代码片段进行抽取,将其通过<sql>标签封装到一个SQL片段,然后再通过<include>标签进行引用。

    • <sql>:定义可重用的SQL片段
    • <include>:通过属性refid,指定包含的SQL片段

5. 事务相关概念

可以将要执行的多个操作看作是一个集合,这个集合中的要么全部执行成功提交,要么执行成功的碰到失败的进行回滚,全部不提交。

面试题:事务有哪些特性?

原子性(Atomicity):事务是不可分割的最小单元,要么全部成功,要么全部失败。
一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
事务的四大特性简称为:ACID

原子性(Atomicity) :原子性是指事务包装的一组sql是一个不可分割的工作单元,事务中的操作要么全部成功,要么全部失败。

一致性(Consistency):一个事务完成之后数据都必须处于一致性状态。

如果事务成功的完成,那么数据库的所有变化将生效。
如果事务执行出现错误,那么数据库的所有变化将会被回滚(撤销),返回到原始状态。
隔离性(Isolation):多个用户并发的访问数据库时,一个用户的事务不能被其他用户的事务干扰,多个并发的事务之间要相互隔离。

 一个事务的成功或者失败对于其他的事务是没有影响。

持久性(Durability):一个事务一旦被提交或回滚,它对数据库的改变将是永久性的,哪怕数据库发生异常,重启之后数据亦然存在。
  • @Transactional注解当中的两个常见的属性:

    1. 异常回滚的属性:rollbackFor
      • 默认情况下,只有出现RuntimeException(运行时异常)才会回滚事务。
      • 假如想让所有的异常都回滚,需要来配置@Transactional注解当中的rollbackFor属性,通过rollbackFor这个属性可以指定出现何种异常类型回滚事务。@Transactional(rollbackFor=Exception.class)
    2. 事务传播行为:propagation
      • 事务的传播行为(propagation属性):当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。
    • REQUIRED【默认值】需要事务,有则加入,无则创建新事务
      REQUIRES_NEW需要新事务,无论有无,总是创建新事务
      SUPPORTS支持事务,有则加入,无则在无事务状态中运行
      NOT_SUPPORTED不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务
      MANDATORY必须有事务,否则抛异常
      NEVER必须没事务,否则抛异常

6. spring的ioc和aop概念,aop底层原理(设计模式)

IOC:Inversion of Control控制反转,将对象的创建和管理权交由IOC容器来进行管理。

AOP:Aspect Oriented Programming(面向切面编程、面向方面编程),面向切面编程就是面向特定方法编程。

AOP面向切面编程的一些优势:

  • 代码无侵入:没有修改原始的业务方法,就已经对原始的业务方法进行了功能的增强或者是功能的改变
  • 减少了重复代码
  • 提高开发效率
  • 维护方便
  1. 连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
    • 连接点指的是可以被aop控制的方法。例如:入门程序当中所有的业务方法都是可以被aop控制的方法。
  2. 通知:Advice,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)。
  3. 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用。
  4. 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
  5. 目标对象:Target,通知所应用的对象
通知类型:

@Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
@Before:前置通知,此注解标注的通知方法在目标方法前被执行
@After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
@AfterReturning : 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
@AfterThrowing : 异常后通知,此注解标注的通知方法发生异常后执行

切入点表达式:

  • execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
    • 其中带?的表示可以省略的部分
    • 可以使用通配符描述切入点
      • * :单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
      • .. :多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
  • @annotation基于注解的方式来匹配切入点方法。
    • @Before(“@annotation(com.yishooo.anno.MyLog)”)

AOP底层原理:动态代理

  • 基于jdk的原生操作(java.lang.reflect)
  • 基于cglib操作(org.springframework.cglib.proxy) spring-core
public interface UserService {
    public void add();
    public void edit();
    public void delete(Integer id);
    public int selectCount();

}
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("保存用户");
    }

    @Override
    public void edit() {
        System.out.println("编辑用户");
    }

    @Override
    public void delete(Integer id) {
        System.out.println("删除" + id);
    }

    @Override
    public int selectCount() {
        System.out.println("统计总记录数");
        return 10;
    }
}
package com.yishooo.jdk;

import com.yishooo.service.UserService;
import com.yishooo.service.impl.UserServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Auther: Yishooo
 * @Date: 2023-5-9 - 05 - 09 - 19:52
 * @Description: 基于jdk的aop底层原理
 */
public class Demo {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();//目标对象
        /**
         * 参数1:类加载对象,传递方式固定,一般目标对象是哪个类,加载器加载的就传递哪个类加载器
         * 参数2:接口的字节码数组,传递方式固定,目标对象所在类实现了哪些接口,就传递哪些接口的字节码数组
         * 参数3:方法调用的处理器,需要在内部的 invoke 方法中编写增强的核心逻辑
         */
        UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                new InvocationHandler() {
            /**
             * 调用代理对象的方法,都会触发invoke
             * @param proxy 代理对象的引用。注意:尽可能不要在 invoke 中操作 proxy,特别是调用它的方法
             * @param method 被调用的代理对象的方法
             * @param args 调用代理对象的方法时传递的实际参数
             * @return 用于控制调用代理对象方法后得到的返回值
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if ("add".equals(method.getName())) {
                    System.out.println("方法执行前");
                    return method.invoke(userService, args);
                } else if ("delete".equals(method.getName())) {
                    args[0] = 100;
                    return method.invoke(userService, args);
                } else if ("selectCount".equals(method.getName())) {
                    return method.invoke(userService, args);
                }
                //其他方法原样调用
                return method.invoke(userService, args);
            }
        });
        proxy.add();
        /**	执行结果:
          * 方法执行前
          * 保存用户
        */
    }
}
package com.yishooo.cglib;

import com.yishooo.service.impl.UserServiceImpl2;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Auther: Yishooo
 * @Date: 2023-5-9 - 05 - 09 - 20:03
 * @Description: 基于cglib的aop底层原理
 */
public class Demo {
    public static void main(String[] args) {
        UserServiceImpl2 userServiceImpl2 = new UserServiceImpl2();//内容与UserServiceImpl一致
        UserServiceImpl2 proxy = (UserServiceImpl2) Enhancer.create(userServiceImpl2.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                if ("add".equals(method.getName())){
                    System.out.println("方法执行前");
                    return method.invoke(userServiceImpl2,args);
                }else if ("delete".equals(method.getName())){
                    args[0] = 100;//修改传入参数9为100
                    return method.invoke(userServiceImpl2,args);
                }else if ("selectCount".equals(method.getName())){
                    return method.invoke(userServiceImpl2, args);
                }
                //其他方法原样调用
                return method.invoke(userServiceImpl2, args);
            }
        });
        proxy.delete(9);//执行结果:删除100
    }
}

7.springboot自动配置原理,springboot常用注解

SpringBoot的自动配置就是当Spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要手动去声明,从而简化了开发,省去了繁琐的配置操作。

自动配置原理源码入口就是@SpringBootApplication注解,在这个注解中封装了3个注解,分别是:

@SpringBootConfiguration
声明当前类是一个配置类
@ComponentScan
进行组件扫描(SpringBoot中默认扫描的是启动类所在的当前包及其子包)
@EnableAutoConfiguration
封装了@Import注解(Import注解中指定了一个ImportSelector接口的实现类)
在实现类重写的selectImports()方法,读取当前项目下所有依赖jar包中META-INF/spring.factories、META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports两个文件里面定义的配置类(配置类中定义了@Bean注解标识的方法)。
当SpringBoot程序启动时,就会加载配置文件当中所定义的配置类,并将这些配置类信息(类的全限定名)封装到String类型的数组中,最终通过@Import注解将这些配置类全部加载到Spring的IOC容器中,交给IOC容器管理。

在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中定义的配置类非常多,而且每个配置类中又可以定义很多的bean,这些bean并不是都会注册到Spring的IOC容器中。在声明bean对象时,上面有加一个以@Conditional开头的注解,这种注解的作用就是按照条件进行装配,只有满足条件之后,才会将bean注册到Spring的IOC容器中。
请添加图片描述

8.jwt

  1. 概念:
    • JWT全称:JSON Web Token 是一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。jwt令牌实质是一个字符串由Header(头),Payload(有效载荷),Signature(签名)三个部分组成,三个部分之间使用英文的点来分割。
  2. 组成:
    • 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{“alg”:“HS256”,“type”:“JWT”}
    • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{“id”:“1”,“username”:“Tom”}
    • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。
  3. 应用场景登录认证。
    • 在浏览器发起请求来执行登录操作,此时会访问登录的接口,如果登录成功之后,需要生成一个jwt令牌,将生成的 jwt令牌返回给前端。
    • 前端拿到jwt令牌之后,会将jwt令牌存储起来。在后续的每一次请求中都会将jwt令牌携带到服务端。
    • 服务端统一拦截请求之后,先来判断一下这次请求有没有把令牌带过来,如果没有带过来,直接拒绝访问,如果带过来了,还要校验一下令牌是否是有效。如果有效,就直接放行进行请求的处理。
  4. JWT是如何将原始的JSON格式数据,转变为字符串的呢?
    • 其实在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码
    • Base64:是一种基于64个可打印的字符来表示二进制数据的编码方式。既然能编码,那也就意味着也能解码。所使用的64个字符分别是A到Z、a到z、 0- 9,一个加号,一个斜杠,加起来就是64个字符。任何数据经过base64编码之后,最终就会通过这64个字符来表示。当然还有一个符号,那就是等号。等号它是一个补位的符号
    • 需要注意的是Base64是编码方式,而不是加密方式。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值