川职院-课堂笔记(节节更新)

每日笔记整理:

2022-05-18

2022-05-19:

IOC容器的作用?

什么是控制反转?

IOC容器的分类:

BeanFactory接口:

​ xmlBeanFactory类实现

ApplicationContext接口:

​ ClassPathXmlApplicationContext类实现

​ FileSystemXmlApplicationContext类实现

​ WebXmlApplicationContext类实现

在Spring中配置bean的内容

常用配置属性:(XML文件中bean标签的属性配置)

1.scope: 配置bean的作用域(默认是单例,singleton),其他属性值:prototype、request、session 和 global session

2.lazy-init:配置bean的实例加载的时间,值为true:在getbean或者需要实例的时候才被初始化

​ 值为false:在容器加载的时候初始化

3.init-method:配置当bean初始化完成后的回调

4.destroy-method:配置当bean销毁后的回调

5.abstract:配置当前bean可以作为一个父元素让子元素bean实现属性的继承

6.parent:配置容器当中其中一个bean作为父元素,继承父元素中所有的属性值

接口化配置内容:
1.初始化接口:实现InitializingBean 接口,实现afterPropertiesSet方法 - 初始化
2.实现DisposableBean 接口,实现destroy方法 -销毁

前后置处理器
作用:能够重用两段代码,在bean的初始化完成之前和之后调用

public class InitHelloWorld implements BeanPostProcessor {
    /*前置处理*/
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("前置处理器处理中!------>"+beanName);
        return bean;
    }
    /*后置处理器*/
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后置处理器处理中!------>"+beanName);
        return bean;
    }
}

bean的生命周期加载顺序图

2022-05-20

什么是依赖注入?(DI)
依赖注入的方法有哪些?该怎么写怎么配置?

构造器注入方法

1.通过构造器注入(引用实例)

 <!-- 准备要注入的实例 -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>


<!-- 准备要实现注入实例的类 -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <!-- 给构造器参数进行赋值,一个constructor-arg代表给第一个赋值 -->
      <constructor-arg ref="spellChecker"/>
   </bean>

2.通过构造器注入(内部bean注入)

<!-- 准备要实现注入实例的类 -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <!-- 给构造器参数进行赋值,一个constructor-arg代表给第一个赋值 -->
       <constructor-arg >
       <bean id="spellChecker" class="com.tutorialspoint.SpellChecker"></bean>
    </constructor-arg>
   </bean>

通过setter方法注入

1.通过属性自动调用setter方法注入

 <!-- 准备要注入的实例 -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>


<!-- 准备要实现注入实例的类 -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <!-- 给成员变量spellChecker 进行引用赋值 -->
      <property name="spellChecker" ref="spellChecker"/>
   </bean>

2.setter内部bean注入

<!-- 准备要实现注入实例的类 -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <bean id="spellChecker" class="com.tutorialspoint.SpellChecker"></bean>
   </bean>

集合类型输入

1.List集合注入

2.Set集合注入

3.Map集合注入

4.Properties注入

集合中引用的注入

bean自动装配

在bean标签上设置autowire属性值

<bean class="..." id=".." autowire="byName">。。。

基于注解化的配置

1. 依赖注入的注解

@Autowired 注解

作用:默认是根据类型完成注入,可以放在setter方法、构造器、成员变量上,自动实现依赖注入

@Autowired(required = false )

代表当前注入的bean非必须,默认情况是必须要完成注入的

@Qualifier注解

配合@Autowired 注解,指定要注入的bean是谁,参数中填写bean的id值或name值

@Resource注解

默认是根据类型自动注入,但是注意idea不会出现错误提示,只有运行后不正确才会报错,@Autowired是会有错误注入提示的。

@Resource(name = "bean的id或name属性值")

@Resource(type = "类名.class")

2.bean 的生命周期函数注解

@PostConstruct :替代在xml中配置init-method 属性

@PreDestroy:替代在xml中配置destroy-method

3.实现容器的配置注解(替代spring.xml的作用)

@Configuration: 标识这是一个配置bean实例的类(放在类声明上)
@Bean: 标识一个返回实例对象的方法(放在方法声明上)

使用注解化容器配置,加载ioc容器方法就发生了改变

1.单个配置类的注册

2.注册多个配置类的方法

5.Bean的作用域配置

@Scope("prototype")
多实例,IOC容器启动创建的时候,并不会创建对象放在容器在容器当中,当你需要的时候,需要从容器当中取该对象的时候,就会创建。
@Scope("singleton")
单实例 IOC容器启动的时候就会调用方法创建对象,以后每次获取都是从容器当中拿同一个对象(map当中)。
@Scope("request")
同一个请求创建一个实例
@Scope("session")
同一个session创建一个实例

2022-05-21

问题:

** AOP是什么?AOP的作用是什么?**
** AOP的实现有几种方法?区别是什么? **

** Aop的术语 **
AOP 领域中的特性术语:

通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
切点(PointCut): 可以插入增强处理的连接点。
切面(Aspect): 切面是通知和切点的结合。
引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。

** 通知的类型 **
前置通知 before 在一个方法执行之前,执行通知。
后置通知 after 在一个方法执行之后,不考虑其结果,执行通知。
返回后通知 after-returning 在一个方法执行之后,只有在方法成功完成时,才能执行通知。
抛出异常后通知 after-throwing 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。

环绕通知 around 在建议方法调用之前和之后,执行通知。

** AOP必须要引入的包 **

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.8.RC3</version>
</dependency>

** 切点表达式写法 **
方法表达式以 * 号开始,标识我们不关心方法的返回值类型。然后我们指定了全限定类名和方法名。对于方法参数列表,我们使用 .. 标识切点选择任意的play方法,无论该方法的入参是什么。

** 各类通知的xml定义方法 **

<aop:config>
   <aop:aspect id="myAspect" ref="aBean">
      <aop:pointcut id="businessService"
         expression="execution(* com.xyz.myapp.service.*.*(..))"/>
      <!-- 前置通知 -->
      <aop:before pointcut-ref="businessService" 
         method="doRequiredTask"/>
      <!-- 后置通知 -->
      <aop:after pointcut-ref="businessService" 
         method="doRequiredTask"/>
      <!-- 返回后通知 -->
      <!--The doRequiredTask method must have parameter named retVal -->
      <aop:after-returning pointcut-ref="businessService"
         returning="retVal"
         method="doRequiredTask"/>
      <!-- 异常后通知 -->
      <!--The doRequiredTask method must have parameter named ex -->
      <aop:after-throwing pointcut-ref="businessService"
         throwing="ex"
         method="doRequiredTask"/>
      <!-- 环绕通知 -->
      <aop:around pointcut-ref="businessService" 
         method="doRequiredTask"/>
   ...
   </aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>

** 理解通知中的作用 **

** demo案例 **


** 环绕通知 **
Spring AOP的环绕通知和前置、后置通知有着很大的区别,主要有两个重要的区别:
1)目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知是不能决定的,它们只是在方法的调用前后执行通知而已,即目标方法肯定是要执行的。joinPoint.proceed()就是执行目标方法的代码。

2)环绕通知可以控制返回对象,即可以返回一个与目标对象完全不同的返回值。虽然这很危险,但是却可以做到。



** ProceedingJoinPoint接口 **

1)获取切入点方法的名字
getSignature());是获取到这样的信息 :返回值类型+ 包名+类名+方法名,
//获取方法名
String methodName = joinPoint.getSignature().getName()2)获取方法上的注解
Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null)
        {xxxxxx annoObj= method.getAnnotation(xxxxxx.class);}
        return null;3)获取方法的参数
这里返回的是切入点方法的参数列表
Object[] args = joinPoint.getArgs();4)调用切入点的方法
有返回值则返回对象,没有返回值则为null
Object res = joinPoint.proceed();

SpringJDBC

Spring JDBC 框架负责所有的低层细节,从开始打开连接,准备和执行 SQL 语句,处理异常,处理事务,到最后关闭连接。

1.引入SpringJDBC依赖,以及mysql驱动依赖

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.15</version>
        </dependency>

        <!-- mysql驱动类 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>

2.配置数据源(在Spring的配置文件中配置)

<!-- mysql数据源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/huawei?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=GMT%2b8" />
        <property name="username" value="root" />
        <property name="password" value="root123456" />
    </bean>

3.创建JdbcTemplate对象

//1.加载容器
      ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

      //2.获取数据源对象
        DriverManagerDataSource dataSource = (DriverManagerDataSource) context.getBean("dataSource");

        //3.创建jdbcTemplate对象,构造器传入数据源对象加载
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

4.查询功能(单行和多行)

 //查询数据,查询返回list集合
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);

        //查询数据,只能查询结果集为一行的数据,封装为map
        Map<String, Object> map = jdbcTemplate.queryForMap(sql);

4.1 查询结果集合java实体(POJO类)字段自动映射

(1)编写一个mapper类实现RowMapper接口

作用:将结果集与实体类字段产生关联

public class UserMapper implements RowMapper<UserDto> {

    @Override
    public UserDto mapRow(ResultSet rs, int rowNum) throws SQLException {

        UserDto dto = new UserDto();

        dto.setCode(rs.getString("name"));
        dto.setName(rs.getString("code"));

        return dto;
    }
}

(2)调用jdbcTemplate的查询结果集与字段映射实现功能

//只能查询结果集为一行的数据,并把结果集数据与实体字段映射封装返回
UserDto userDto = jdbcTemplate.queryForObject(sql, new UserMapper());

//查询多行数据,并把结果集数据与实体字段映射封装返回
List<UserDto> query = jdbcTemplate.query(sql2, new UserMapper());

2022-05-22

Spring包的自动扫描

1.开启以及配置包的自动扫描(在Spring.xml文件中)

<context:component-scan base-package="cn.itcast.*" />   填写要扫描的包结构  

在xml配置了这个标签后,spring可以自动去扫描base-pack下面或者子包下面的java文件,如果扫描到有@Component @Controller@Service等这些注解的类,则把这些类注册为bean

另外context:component-scan还提供了两个子标签
(1)context:include-filter

(2)context:exclude-filter
在说明这两个子标签前,先说一下context:component-scan
有一个use-default-filters属性,该属性默认为true,这就意味着会扫描指定包下的全部的标有@Component的类,包含子注解@Service,@Reposity等,并注册成bean

1.context:incluce-filter

<context:component-scan base-package="com.huawei.*" use-default-filters="false">  
<context:include-filter type="annotation"expression="org.springframework.stereotype.Controller"/>   
</context:component-scan> 

这样就会只扫描base-package指定下的有@Controller下的java类,并注册成bean
这里要注意:如果加上use-default-filters="false"则默认情况下是true,可能会出现扫描到非@Controller注解的类加载为bean,所以指定扫描注解一定要加上use-default-filters="false"配置。

2.context:exclude-filter

<context:component-scan base-package="com.huawei.*" >  
<context:exclude-filter type="annotation"expression="org.springframework.stereotype.Controller"/>   
</context:component-scan> 

另外在我参与的项目中可以发现在base-package指定的包中有的子包是不含有注解了,所以不用扫描,此时可以指定context:exclude-filter来进行过滤,说明此包不需要被扫描

总结:

context:exclude-filter指定的不扫描
context:include-filter指定的扫描

Lombok常用注解

1.添加lombok依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
</dependency>

lombok系统图

(1)自动产生 getter/setter方法

(2)自动重写 toString() 方法,会印出所有变量

(3)自动生成 equals(Object other) 和 hashcode() 方法,包括所有非静态变量和非 transient 的变量

如果某些变量不想要加进判断,可以透过 exclude 排除,也可以使用 of 指定某些字段

(4)生成一个没有参数的构造器

(5)生成一个包含所有参数的构造器

(6)生成一个包含 "特定参数" 的构造器特定参数指的是那些有加上 final 修饰词的变量们

(7)综合注解@Data

整合了以下注解:

@Getter/@Setter
@ToString
@EqualsAndHashCode
@RequiredArgsConstructor

2022-05-23

SpringMVC执行流程

SpringMVC 的执行流程如下。
用户点击某个请求路径,发起一个 HTTP request 请求,该请求会被提交到 DispatcherServlet(前端控制器);
由 DispatcherServlet 请求一个或多个 HandlerMapping(处理器映射器),并返回一个执行链(HandlerExecutionChain)。
DispatcherServlet 将执行链返回的 Handler 信息发送给 HandlerAdapter(处理器适配器);
HandlerAdapter 根据 Handler 信息找到并执行相应的 Handler(常称为 Controller);
Handler 执行完毕后会返回给 HandlerAdapter 一个 ModelAndView 对象(Spring MVC的底层对象,包括 Model 数据模型和 View 视图信息);
HandlerAdapter 接收到 ModelAndView 对象后,将其返回给 DispatcherServlet ;
DispatcherServlet 接收到 ModelAndView 对象后,会请求 ViewResolver(视图解析器)对视图进行解析;
ViewResolver 根据 View 信息匹配到相应的视图结果,并返回给 DispatcherServlet;
DispatcherServlet 接收到具体的 View 视图后,进行视图渲染,将 Model 中的模型数据填充到 View 视图中的 request 域,生成最终的 View(视图);
视图负责将结果显示到浏览器(客户端)。

Spring MVC 涉及到的组件有:
DispatcherServlet(前端控制器)
HandlerMapping(处理器映射器)
HandlerAdapter(处理器适配器)
Handler(处理器)
ViewResolver(视图解析器)
View(视图)

视图解析器
视图解析器(ViewResolver)是 Spring MVC 的重要组成部分,负责将逻辑视图名解析为具体的视图对象。

<!-- 配置视图解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

注意:注意你创建的文件夹名称和后缀与视图解析器的匹配规则一致

**@Controller注解 **
@Controller 注解用于声明某类的实例是一个控制器。

Spring MVC 使用扫描机制找到应用中所有基于注解的控制器类,所以,为了让控制器类被 Spring MVC 框架扫描到,需要在配置文件中声明 spring-context,并使用 context:component-scan/ 元素指定控制器类的基本包(请确保所有控制器类都在基本包及其子包下)

@RequestMapping

一个控制器内有多个处理请求的方法,如 UserController 里通常有增加用户、修改用户信息、删除指定用户、根据条件获取用户列表等。每个方法负责不同的请求操作,而 @RequestMapping 就负责将请求映射到对应的控制器方法上。

在基于注解的控制器类中可以为每个请求编写对应的处理方法。使用 @RequestMapping 注解将请求与处理方法一 一对应即可。

@RequestMapping 注解可用于类或方法上。用于类上,表示类中的所有响应请求的方法都以该地址作为父路径。

@Controller
@RequestMapping("/sys")
public class SysController {

    /**
     * 页面跳转的开发
     * @return
     */
   @RequestMapping("/login")
   public String toLogin(){
       System.out.println("跳转到登录页面的方法");
       return "login";//逻辑视图名称 通过视图解析器自动拼接解析 /WEB-INF/views/login.jsp
   }

}

2022-05-24

HTTP响应状态码:

404 : 请求或访问的资源不存在

405 :请求方法不允许

400:请求参数异常

500 :后端出现系统bug性异常,而且异常抛出至controller控制器方法上

@RequestMapping注解配置属性

(1)value 属性

value 属性是 @RequestMapping 注解的默认属性,因此如果只有 value 属性时,可以省略该属性名,如果有其它属性,则必须写上 value 属性名称。

value 属性支持通配符匹配,如 @RequestMapping(value="toUser/*") 表示 http://localhost:8080/toUser/1http://localhost:8080/toUser/hahaha 都能够正常访问

(2)path属性

path 属性和 value 属性都用来作为映射使用。即 @RequestMapping(value="toUser") 和 @RequestMapping(path="toUser") 都能访问 toUser() 方法。

(3)name属性

name属性相当于方法的注释,使方法更易理解。如 @RequestMapping(value = "toUser",name = "获取用户信息")。

(4)method属性

method 属性用于表示该方法支持哪些 HTTP 请求。如果省略 method 属性,则说明该方法支持全部的 HTTP 请求。

@RequestMapping(value = "toUser",method = RequestMethod.GET) 表示该方法只支持 GET 请求。也可指定多个 HTTP 请求,如 @RequestMapping(value = "toUser",method = {RequestMethod.GET,RequestMethod.POST}),说明该方法同时支持 GET 和 POST 请求。

(5)params属性

params 属性用于指定请求中规定的参数

以上代码表示请求中必须包含 type 参数时才能执行该请求。即 http://localhost:8080/toUser?type=xxx 能够正常访问 toUser() 方法,而 http://localhost:8080/toUser 则不能正常访问 toUser() 方法

以上代码表示请求中必须包含 type 参数,且 type 参数为 1 时才能够执行该请求。即 http://localhost:8080/toUser?type=1 能够正常访问 toUser() 方法,而 http://localhost:8080/toUser?type=2 则不能正常访问 toUser() 方法。

SpringMVC-controller方法接收请求参数的方法

(1)使用HttpServletRequest对象的getParameter方法接收

/**
     * 页面跳转的开发  ( 当前请求只能通过post请求访问)
     * @return
     */
   @RequestMapping(value="/login",method = RequestMethod.GET)
   public String toLogin(HttpServletRequest request) throws IOException {
       System.out.println("跳转到登录页面的方法");
       request.setCharacterEncoding("UTF-8");

       //通过Servlet API的方法来获取请求的参数 getParameter
       String name = request.getParameter("name");

       System.out.println("name参数:"+name);

       return "login";//逻辑视图名称 通过视图解析器自动拼接解析 /WEB-INF/views/login.jsp
   }

SpringMVC-controller方法-返回数据集到视图层的方法

(1)使用SpringMVC的Model对象,调用addAttribute

@RequestMapping(value="/login",method = RequestMethod.GET)
   public String toLogin(Model model) throws IOException {
       System.out.println("跳转到登录页面的方法");

       //设置返回前端的数据(键值对设置方法)
       model.addAttribute("key","value");  // ${key}

       //设置返回一个对象内容

       Dog dog = new Dog();

       dog.setName("哈哈");
       dog.setType("金毛");

       model.addAttribute(dog);  // ${dog.name}   哈哈   {dog.type}  金毛

       return "login";//逻辑视图名称 通过视图解析器自动拼接解析 /WEB-INF/views/login.jsp
   }

jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>登录页面</title>
</head>
<body>
    欢迎来到登录页面
    ${dog.name}
    ${dog.type}
</body>
</html>

登录-判断-页面跳转课程案例

1.java代码-controller控制器代码

@Controller
@RequestMapping("/sys")
public class SysController {

    /**
     * 页面跳转的开发  ( 当前请求只能通过post请求访问)
     * @return
     */
   @RequestMapping(value="/login",method = RequestMethod.GET)
   public String toLogin(Model model,HttpServletRequest request) throws IOException {
       System.out.println("进行登录判断操作方法...");

       String userNamer = request.getParameter("userNamer");

       String pwd = request.getParameter("pwd");

       String sys_userName = "root";
       String sys_pwd = "123456";

       if(sys_userName.equals(userNamer)&&sys_pwd.equals(pwd)){
           //登录成功-》登录成功页面

           model.addAttribute("userName",userNamer); //${userName}

           return "ok";
       }else{
           //登录失败
           return "notOk";
       }
   }
}

2.登录页面,编写在webapp根目录下的index.jsp页面,这样当项目启动时就可以访问登录页面

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <meta charset="UTF-8" />
    <title>登录</title>
</head>
<body>

<form action="${pageContext.request.contextPath}/sys/login" method="get">
    <input type="text" name="userNamer" placeholder="请输入用户名"/><br/>
    <input type="password" name="pwd" placeholder="请输入密码" /><br/>
    <input type="submit" value="登录" />
</form>

</body>
</html>

3.成功页面,通过el表达式取出返回到视图层的数据

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>登录成功</title>
</head>
<body>
    欢迎进入系统!${userName}....
</body>\
</html>

4.失败页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录失败</title>
</head>
<body>
   用户名或密码错误!....
</body>
</html>

SpringMVC参数的传递方式

(1)通过实体Bean接收请求参数

(2)通过处理方法的形参接收请求参数

通过处理方法的形参接收请求参数就是直接把表单参数写在控制器类相应方法的形参中,即形参名称与请求参数名称完全相同。该接收参数方式适用于 get 和 post 提交请求方式。

(3)通过HttpServletRequest接收请求参数

通过 HttpServletRequest 接收请求参数适用于 get 和 post 提交请求方式

(4)通过@PathVariable接收URL中的请求参数

通过 @PathVariable 获取 URL 中的参数

在访问“http://localhost:8080/springMVCDemo02/user/login/bianchengbang/123456”路径时,上述代码会自动将 URL 中的模板变量 {name} 和 {pwd} 绑定到通过 @PathVariable 注解的同名参数上,即 name=bianchengbang、pwd=123456。

(5)通过@RequestParam定义接收的请求参数

在方法入参处使用 @RequestParam 注解指定其对应的请求参数。@RequestParam 有以下三个参数:
value:参数名
required:是否必须,默认为 true,表示请求中必须包含对应的参数名,若不存在将抛出异常
defaultValue:参数默认值
通过 @RequestParam 接收请求参数适用于 get 和 post 提交请求方式
该方式与“通过处理方法的形参接收请求参数”部分的区别如下:当请求参数与接收参数名不一致时,“通过处理方法的形参接收请求参数”不会报 400错误,而“通过 @RequestParam 接收请求参数”会报 400 错误。

请求的重定向和请求的转发

Spring MVC 请求方式分为转发、重定向 2 种,分别使用 forwardredirect 关键字在 controller 层进行处理。

请求转发:

客户浏览器发送 http 请求,Web 服务器接受此请求,调用内部的一个方法在容器内部完成请求处理和转发动作,将目标资源发送给客户;在这里转发的路径必须是同一个 Web 容器下的 URL,其不能转向到其他的 Web 路径上,中间传递的是自己的容器内的 request。

请求重定向:

客户浏览器发送 http 请求,Web 服务器接受后发送 302 状态码响应及对应新的 location 给客户浏览器,客户浏览器发现是 302 响应,则自动再发送一个新的 http 请求,请求 URL 是新的 location 地址,服务器根据此请求寻找资源并发送给客户。

在这里 location 可以重定向到任意 URL,既然是浏览器重新发出了请求,那么就没有什么 request 传递的概念了。在客户浏览器的地址栏中显示的是其重定向的路径,客户可以观察到地址的变化。重定向行为是浏览器做了至少两次的访问请求。

转发重定向到非视图解析器资源时

配置静态资源目录,一定要在webapp根目录

在dispacther-servlet.xml配置文件中配置:

<mvc:annotation-driven />
    <mvc:resources location="/static/" mapping="/static/**" />

SpringMVC标准开发模式

1.分层架构,controller层处理请求和响应,service以及serviceimpl层作为业务的接口和业务的实现层

优点:分层架构的模式可以让我们的代码解耦,让代码更优雅,且内聚少低耦合。

案例演示:

(1)控制器层

/**
 * 用户管理-控制器层
 */
@Controller
@RequestMapping("/user")
public class UserController {

    //注入接口实现
    @Resource(name = "oracleUserService")
    private UserService userService;

    /**
     * 查询用户信息
     * @return
     */
    @RequestMapping(value = "/getUser",method = RequestMethod.GET)
    public String getUserData(){

        userService.getUserData();

        return null;
    }

}

(2)接口层

/**
 * 用户管理-业务-接口层
 * 2022/5/24
 */
public interface UserService {

    String getUserData();

}

(3)接口实现层

实现类1

@Service
public class UserServiceImpl implements UserService {

    @Override
    public String getUserData() {

        System.out.println("UserServiceImpl-实现");

        return null;
    }
}

实现类2

@Service
public class OracleUserService implements UserService {
    @Override
    public String getUserData() {

        System.out.println("OracleUserService实现");

        return null;
    }
}

2022-05-25

类型转换器

Spring MVC 框架的 Converter<S,T> 是一个可以将一种数据类型转换成另一种数据类型的接口,这里 S 表示源类型,T 表示目标类型。开发者在实际应用中使用框架内置的类型转换器基本上就够了,但有时需要编写具有特定功能的类型转换器。

类型转换器的工作时机

类型转换是在视图与控制器相互传递数据时发生的。Spring MVC 框架对于基本类型(例如 int、long、float、double、boolean 以及 char 等)已经做好了基本类型转换。
注意:在使用内置类型转换器时,请求参数输入值与接收参数类型要兼容,否则会报 400 错误。

SpringMVC内置转换器

自定义类型转换器

例如需要用户在页面表单中输入信息来创建商品信息。当输入“gaojingbo,27,2.3”时表示在程序中自动创建一个 new User,并将“gaojingbo”值自动赋给 name 属性,将“27”值自动赋给 age 属性,将“2.3”值自动赋给 height 属性。
如果想实现上述应用,需要做以下 5 件事:

  1. ​ 创建实体类。
  2. ​ 创建控制器类。
  3. ​ 创建自定义类型转换器类。
  4. ​ 注册类型转换器。

(1)创建实体类(UserDto)

import lombok.Data;

/**
 * 转换的目标实体 UserDto
 * 2022/5/25
 */
@Data
public class UserDto {

    private String name;

    private Integer age;

    private Double height;

}

(2) 创建自定义转换类

/**
 * String 转换为 UserDto的转换器
 * 2022/5/25
 */
@Component
public class String2UserDtoConvter implements Converter<String, UserDto> {

    /**
     *  手动编写转换
     * @param s  源数据
     * @return 返回转换的数据
     */
    @Override
    public UserDto convert(String s) { //name,age,height

        UserDto dto = new UserDto();

        String[] split = s.split(","); //[name,age,height];

        if(split.length!=3){

            throw new IllegalArgumentException("String2UserDtoConvter类型转换错误,源数据类型必须是:name,age,height");

        }else{
            dto.setName(split[0]);
            dto.setAge(Integer.valueOf(split[1]));
            dto.setHeight(Double.valueOf(split[2]));

            return dto;
        }
    }
}

(3)注册类型转换器 (在springMVC视图解析器配置文件中)

<!-- 注册类型转换器 -->
    <mvc:annotation-driven conversion-service="conversionService" />
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <!-- 可以注册多个自定义的类型转换器 -->
            <list>
                <bean class="com.huawei.sys.config.String2UserDtoConvter"/>
            </list>
        </property>
    </bean>

(4)编写控制器层代码,定义接收参数

@RequestMapping("/s2user")
   public String StringToUserTest(@RequestParam("user") Date date){

       System.out.println("测试转换:String-》LocalDate");
       System.out.println(date);

       return "ok";
   }

数据格式化(Formatter)

Spring MVC 框架的 FormatterConverter<S, T> 一样,也是一个可以将一种数据类型转换成另一种数据类型的接口。不同的是,Formatter 的源类型必须是 String 类型,而 Converter 的源类型可以是任意数据类型。Formatter 更适合 Web 层,而 Converter 可以在任意层中。所以对于需要转换表单中的用户输入的情况,应该选择 Formatter,而不是 Converter。

在 Web 应用中由 HTTP 发送的请求数据到控制器中都是以 String 类型获取,因此在 Web 应用中选择 Formatter 比选择 Converter<S, T> 更加合理。

Spring MVC 提供了几个内置的格式化转换器

​ NumberFormatter:实现 Number 与 String 之间的解析与格式化。
​ CurrencyFormatter:实现 Number 与 String 之间的解析与格式化(带货币符号)。
​ PercentFormatter:实现 Number 与 String 之间的解析与格式化(带百分数符号)。
​ DateFormatter:实现 Date 与 String 之间的解析与格式化。

自定义格式化转换器就是编写一个实现 org.springframework.format.Formatter 接口的 Java 类。

这里的 T 表示由字符串转换的目标数据类型。该接口有 parse 和 print 两个接口方法,自定义格式化转换器类必须覆盖它们。

(1)parse 方法:

的功能是利用指定的 Locale 将一个 String 类型转换成目标类型,

(2)print 方法:

与之相反,用于返回目标对象的字符串表示。

案例,实现实体中Date字段与String字段转换

(1)编写实体类

/**
 * 转换的目标实体 UserDto
 * 2022/5/25
 */
@Data
public class UserDto {

    private String name;

    private Integer age;

    private Double height;

    private Date time;
}

(2)编写formatter类

/**
 * String -> Date格式化类
 * 2022/5/25
 */
public class String2DateFormatter implements Formatter<Date> {

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * String -> 目标
     * @param s
     * @param locale
     * @return
     * @throws ParseException
     */
    @Override
    public Date parse(String s, Locale locale) throws ParseException {
        return sdf.parse(s);
    }

    /**
     * 目标 -》 String
     * @param date
     * @param locale
     * @return
     */
    @Override
    public String print(Date date, Locale locale) {
        return sdf.format(date);
    }
}

(3)注册formatter类

<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="formatters">
            <!-- 可以注册多个自定义的String转换器 -->
            <set>
                <bean class="com.huawei.sys.config.String2DateFormatter" />
            </set>
        </property>
    </bean>

(4)控制器层当出现参数传递,自动实现转换

@RequestMapping("/s2user")
   public String StringToUserTest(UserDto dto){

       System.out.println("测试转换:String-》UserDto");
       System.out.println(dto);

       return "ok";
   }

2022-05-26

JavaScript中json对象与字符串的相互转换方法

//js对象
           var obj = {
               name:"张三",
               age:18,
               sons:["老大","老二","老六"]
           };

           console.dir(obj);

           //对象 -》 json字符串
           let jsonStr = JSON.stringify(obj);
           console.dir(jsonStr);

           //json字符串变为json对象或js对象
           var parse = JSON.parse(jsonStr);
           console.dir(parse);

JQuery-ajax写法

$.ajax({
               url:"${pageContext.request.contextPath}/sys/getUser",
               method:"GET",//请求方法
               async:false,// 异步参数值为true时:接口请求是异步执行的,为false是同步执行的
               data:{name:"张三",age:18},//传递json字符串
               contentType:"application/json",//请求报文内容是json
               dataType:"JSON",//数据传递的内容都是json(请求和响应)
               success:function(data){//如果请求成功,执行success回调,data就是后端返回到前端的数据(一般就是json数据)
                   console.dir(data);
                   console.dir("2.成功");
               },
               error:function(err){//如果请求失败,error回调,err是后端系统异常抛出的数据
                   console.dir(err);
               }
           });

Web开发中json的数据传递内容

(1)前端发送json数据到后端

1.post请求类型情况

post的要求:

(1)请求的参数是保存在请求体中的;

(2)想要发送json数据时,请求参数必须是json字符串(使用JSON.stringify方法把json对象变成json字符串)

(3)后端controller方法中接收参数的javabean必须要添加@RequestBody注解

前端ajax代码:

$.ajax({
               url:"${pageContext.request.contextPath}/sys/getUser",
               method:"POST",//请求方法
               async:false,// 异步参数值为true时:接口请求是异步执行的,为false是同步执行的
               data:JSON.stringify({name:"张三",age:18}),//传递json字符串
               contentType:"application/json",//请求报文内容是json
               dataType:"JSON",//数据传递的内容都是json(请求和响应)
               success:function(data){//如果请求成功,执行success回调,data就是后端返回到前端的数据(一般就是json数据)
                   console.dir(data);
                   console.dir("2.成功");
               },
               error:function(err){//如果请求失败,error回调,err是后端系统异常抛出的数据
                   console.dir(err);
               }
           });

后端实体类

/**
 * 转换的目标实体 UserDto
 * 2022/5/25
 */
@Data
public class UserDto {

    private String name;

    private Integer age;

    private Double height;

    private Date time;
}

后端controller

@RequestMapping(value = "/getUser",method = RequestMethod.POST)
   @ResponseBody
   public UserDto getUser(@RequestBody UserDto dto2) throws InterruptedException {

       System.out.println("调用到方法!");

       Thread.sleep(10000);

       System.out.println(dto2);

       return dto2;//@ResponseBody 让返回的java对象变成一段json
   }

2.get请求类型情况

GET请求不能发送JSON数据

GET请求只能发送普通表单数据

前端ajax代码

$.ajax({
               url:"${pageContext.request.contextPath}/sys/getUser",
               method:"GET",//请求方法
               async:false,// 异步参数值为true时:接口请求是异步执行的,为false是同步执行的
               data:{name:"张三",age:18},//传递json字符串
               contentType:"application/json",//请求报文内容是json
               dataType:"JSON",//数据传递的内容都是json(请求和响应)
               success:function(data){//如果请求成功,执行success回调,data就是后端返回到前端的数据(一般就是json数据)
                   console.dir(data);
                   console.dir("2.成功");
               },
               error:function(err){//如果请求失败,error回调,err是后端系统异常抛出的数据
                   console.dir(err);
               }
           });

后端controller代码

@RequestMapping(value = "/getUser",method = RequestMethod.GET)
   @ResponseBody
   public UserDto getUser(UserDto dto2) throws InterruptedException {

       System.out.println("调用到方法!");

       Thread.sleep(10000);

       System.out.println(dto2);

       return dto2;//@ResponseBody 让返回的java对象变成一段json
   }

SpringMVC数据校验问题

1.需要引入数据校验相关包

    <!-- 数据校验 -->
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.logging</groupId>
        <artifactId>jboss-logging</artifactId>
        <version>3.1.0.CR2</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.1.0.Final</version>
    </dependency>

2.在controller方法接收参数实体中添加校验注解

/**
 * 转换的目标实体 UserDto
 * 2022/5/25
 */
@Data
public class UserDto {

    @NotNull(message = "用户名不能为空")
    private String name;

    private Integer age;

    private Double height;

    private Date time;
}

3.在controller方法参数前添加@Valid注解

当前端请求进来时,就会自动完成数据校验

@RequestMapping(value = "/getUser",method = RequestMethod.GET)
   @ResponseBody
   public UserDto getUser(@Valid UserDto dto2, BindingResult result) throws InterruptedException {

       System.out.println("调用到方法!");

       if(result.hasErrors()){//返回true说明校验出现错误
           //获取异常信息的列表
           List<ObjectError> allErrors = result.getAllErrors();

           //遍历输出错误信息
           for(ObjectError err: allErrors){
               System.out.println(err.getDefaultMessage());
           }

       }

       return dto2;//@ResponseBody 让返回的java对象变成一段json
   }

}

SpringMVC配置REST接口风格

Spring REST 风格可以简单理解为:使用 URL 表示资源时,每个资源都用一个独一无二的 URL 来表示,并使用 HTTP 方法表示操作,即准确描述服务器对资源的处理动作(GET、POST、PUT、DELETE),实现资源的增删改查
GET:表示获取资源(查询)
POST:表示新建资源(保存数据、登录、文件上传、下载)
PUT:表示更新资源(修改数据)
DELETE:表示删除资源(删除资源数据)

1.引入jackson依赖(确定是否引入)

  <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.12.3</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.12.3</version>
    </dependency>

2.配置一个过滤器

作用:由于 HTTP 不支持 PUT 和 DELETE 请求,所以需要将 DELETE 和 PUT 请求转换成 POST 请求,在 web.xml 中配置过滤器 HiddenHttpMethodFilter。

配置在web.xml文件中

<!-- HTTP请求REST的配置 -->
  <filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

注意:如果你的webapp标签报错,web-app开始标签替换成以下内容:

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

测试一个DELETE请求

1.ajax代码

$.ajax({
               url:"${pageContext.request.contextPath}/sys/test1",
               method:"DELETE",//请求方法
               async:false,// 异步参数值为true时:接口请求是异步执行的,为false是同步执行的
               data:null,//传递json字符串
                dataType:"JSON",//数据传递的内容都是json(请求和响应)
               success:function(data){//如果请求成功,执行success回调,data就是后端返回到前端的数据(一般就是json数据)
                   console.dir(data);
                   console.dir("2.成功");
               },
               error:function(err){//如果请求失败,error回调,err是后端系统异常抛出的数据
                   console.dir(err);
               }
           });

2.controller代码

@RequestMapping(value = "/test1",method = RequestMethod.DELETE)
   @ResponseBody
   public Map testMethod(){
       System.out.println("请求put类型接口");
       return null;
   }

上午作业案例:

1.定义一个注册页面,有表单项目用户名、密码、生日(日期选择器)
2.提交表单的方法使用JavaScript实现绑定,当点击提交按钮的时候触发ajax提交后端接口
3.后端是post请求,前端要发送一个json字符串如何发送
4.后端接收请求成功后,将接收的参数封装成json返回前端
5.返回前端后前端ajax接收后端返回的数据,将数据输出到一个自定义的div中,用span或者其他文字标签展示内容

代码案例:

(1)controller代码

package com.huawei.sys.controller;


import com.huawei.sys.dto.RegisterDto;
import com.huawei.sys.service.UserService;
import com.huawei.sys.service.impl.OracleUserService;
import com.huawei.sys.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;

/**
 * 用户管理-控制器层
 */
@Controller
@RequestMapping("/user")
public class UserController {

    /**
     * 首先得有方法跳转到注册页面才能进行注册操作
     * 注意:方法返回值类型为String,返回逻辑视图名
     * 因为是页面的跳转所以不要添加@ResponseBody注解
     * @return
     */
    @RequestMapping(value = "/toRegister",method = RequestMethod.GET)
    public String toRegister(){
        System.out.println("跳转到注册页面!");
        return "register";//返回注册页面的逻辑视图名称
    }


    /**
     * 注册用户的方法
     * 注意:因为会出现数据的保存操作,所以建议使用post请求,而且加上要传递json数据所以必须使用post请求
     * @ResponseBody 注解:让返回数据封装为json数据发送到前端
     * @RequestBody 注解:从请求体中取出数据和RegisterDto类属性字段值映射保存
     * @param dto
     * @return
     */
    @RequestMapping(value = "/toAddUser",method = RequestMethod.POST)
    @ResponseBody
    public RegisterDto toRegister(@RequestBody RegisterDto dto){
        System.out.println("用户注册");

        System.out.println(dto);

        return dto;
    }

}

(2)参数实体代码

package com.huawei.sys.dto;

import lombok.Data;

import java.util.Date;

/**
 * 用户注册实体
 * 2022/5/26
 */
@Data
public class RegisterDto {

    private String userName;//用户名

    private String pwd;//密码

    /**
     * 注意生日是java.util.Date类型数据,想要实现参数String转Date要编写数据格式化类(Formatter)或者类型转换器(Convrter)
     */
    private Date birthday;//生日

}

(3)注册jsp页面

<%--
  Created by IntelliJ IDEA.
  User: 高
  Date: 2022/5/26
  Time: 11:18
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <meta charset="UTF-8" />
    <!-- 因为要使用到jQuery-ajax 所以要引入jQuery -->
    <script type="text/javascript" src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.min.js"></script>
    <title>注册页面</title>
</head>
<body>

<!-- 注册表单 因为表单提交行为将由js触发js方法实现ajax提交,所以不用编写action属性和method属性-->
<!-- 给表单定义一个id属性,方便获取表单的数据,给每个表单元素都添加一个id方便获取数据 -->
<form id="myForm">
    <label>用户名</label>
    <input type="text" name="userName" id="userName" placeholder="请输入用户名"/><br/>
    <label>密码</label>
    <input type="password" name="pwd" id="pwd" placeholder="请输入密码"/><br/>
    <label>生日</label>
    <input type="date" name="birthday" id="birthday" /><br/>
    <!-- 表单提交按钮行为要关闭,所以一定要定义type="button" 让按钮不再拥有表单提交功能 -->
    <!-- 通过onclick事件元素属性绑定当单击鼠标点击按钮时触发的JavaScript方法toAddUser -->
    <input type="button" value="保存" onclick="toAddUser()"/>
</form>

<!-- 定义JavaScript内容 -->
<script type="text/javascript">

    //定义当点击保存时触发的方法
    function toAddUser(){

        //创建一个数据对象保存表单中的数据
        var formData = {
            //使用jQuery的方法获取表单元素的值
            userName:$("#userName").val(),
            pwd:$("#pwd").val(),
            birthday:$("#birthday").val()
        }
        //输出结果观察
        console.dir(formData);

        //方法触发后执行ajax代码,提交数据到后端接口中
        $.ajax({
            url:"${pageContext.request.contextPath}/user/toAddUser",
            method:"POST",//请求方法
            async:false,// 异步参数值为true时:接口请求是异步执行的,为false是同步执行的
            data:JSON.stringify(formData),//传递json字符串
            contentType:"application/json",
            dataType:"JSON",//数据传递的内容都是json(请求和响应)
            success:function(data){//如果请求成功,执行success回调,data就是后端返回到前端的数据(一般就是json数据)
                console.dir(data);
            },
            error:function(err){//如果请求失败,error回调,err是后端系统异常抛出的数据
                console.dir(err);
            }
        });

    }

</script>

</body>
</html>

posted @   忙碌的高师傅  阅读(654)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示