IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 华清远见 框架阶段总结 -> 正文阅读

[Java知识库]华清远见 框架阶段总结

框架阶段总结

framework:框架 ,根据一些编程思想, 把一些功能封装起来,帮助更好的,更快的做软件开发, 发

布为jar包, 供其他程序员使用,这样的一些软件,被称为框架, 比如spring , spring mvc , mybatis, hibernate , spring boot 等

框架阶段学习了Spring、SpringMvc、Mybatis、SpringBoot、MybatisPlus和SpringBoot-JPA框架

1.Spring

1.1Spring中的几个概念

  • IoC(Inversion of Control):控制反转,由Spring框架创建对象,管理对象和对象之间的依赖关系。

  • DI(Dependency Injection):依赖注入,在程序运行期间,IOC容器动态地将对象需要的外部资源注入到对象中使用,依赖注入的方式有构造器注入、set注入、注解输入,IoC是通过DI来实现的。

  • bean:是由Spring框架创建的对象。

  • pojo(Plain Ordinary Java Object):简单的Java类,只有私有属性和公开set/get方法等的类。

  • AOP( Aspect-Oriented Programming ):面向切面编程,是将程序中重复分散的非业务逻辑代码(如日志、事务等)进行集中的管理,在需要使用时“切入”到程序中运行,AOP可以提高代码的可重复利用性,可维护性,降低对象之间的耦合度。

1.2使用Spring框架

1.2.1导入spring mvc的jar包

<!--    spring mvc的jar包-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.21</version>
    </dependency>

1.2.2创建Spring框架的xml文件

通常命名为applicationContext.xml,放在resources下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

1.2.3定义java类,在spring的xml文件中配置bean对象

package com.xsh.entity;

public class Phone {
    private String brand;
    private double price;
    private int memory;
    //构造函数
    //get/ser方法
}

有三种方式创建对象

  • 调用构造函数
  • 调用自己的静态方法
  • 调用容器中的其他bean的方法,创建对象
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--id:给名字设置的唯一标志,可以通过id找到这个bean对象
        class:类的全名,用于表示bean的类型
        如果没有指定使用哪一个构造函数,默认使用无参构造函数
    -->
    <bean id="p1" class="com.xsh.entity.Phone"></bean>
<!-- 创建对象方式1,调用构造函数-->
    <bean id="date" class="java.util.Date"></bean>
<!-- 创建对象方式2,调用自己的静态方法
        factory-method属性用于指定需要调用的静态方法的名字
  -->
    <bean id="cal" class="java.util.Calendar" factory-method="getInstance"></bean>
<!--  创建对象方式3,调用容器中的其他bean的方法,创建对象
    factory-bean指定调用的容器中的其他bean的名字
  -->
    <bean id="date1" class="java.util.Date" factory-bean="cal" factory-method="getTime"></bean>
</beans>

1.2.4创建Spring的容器,在容器中获取对象,使用对象

public class PhoneTest {
    @Test
    public void getPhone() {
//        1.创建出spring的容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println("ac:" + ac);
//        2.通过容器对象,获取bean
        Phone p1 = ac.getBean("p1", Phone.class);
//        3.使用对象
        p1.setBrand("华为");
        System.out.println(p1.getBrand());
//        ***类型
        System.out.println(p1.getClass());
        System.out.println(Phone.class);
//        4.容器关闭
    }
}

1.3spring的xml中初始化bean的方式及bean标签的属性

1.3.1创建对象的方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--1.构造函数初始化
                如果没有设置constructor-arg这个内容,表示调用无参构造函数
                如果设置了,表示调用对应的构造器函数
                8种基本数据类型和String会自动转换,用value属性表示
    -->
    <bean id="phone" class="com.xsh.entity.Phone">
        <constructor-arg name="brand" value="华为"></constructor-arg>
        <constructor-arg name="price" value="200.0"></constructor-arg>
        <constructor-arg name="memory" value="128"></constructor-arg>
    </bean>
    <bean id="phone1" class="com.xsh.entity.Phone">
        <constructor-arg index="0" value="三星"></constructor-arg>
        <constructor-arg index="1" value="300.0"></constructor-arg>
        <constructor-arg index="2" value="256"></constructor-arg>
    </bean>
    <bean id="str" class="java.lang.String">
        <constructor-arg index="0" value="alice"></constructor-arg>
    </bean>
    <bean id="person" class="com.xsh.entity.Person">
        <!--        ref属性:表示引用容器中存在的bean对象-->
        <constructor-arg name="name" ref="str"></constructor-arg>
        <constructor-arg name="phone" ref="phone1"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
        <!--        <property name="name" value="name"></property>-->
    </bean>
    <!--
        2.set注入:调用set方法,get属性赋值
        property属性,表示给对象的属性赋值,name是属性名,value/ref是对应的值
    -->
    <bean id="person1" class="com.xsh.entity.Person">
        <property name="name" value="tom"></property>
        <property name="phone" ref="phone"></property>
        <property name="age" value="19"></property>
    </bean>

    <bean id="teacher" class="com.xsh.entity.Teacher">
        <constructor-arg name="name" value="张老师"></constructor-arg>
        <constructor-arg name="level" value="6"></constructor-arg>
    </bean>
    <bean id="cat" class="com.xsh.entity.Cat">
        <constructor-arg name="name" value="团团"></constructor-arg>
        <constructor-arg name="sex" value=""></constructor-arg>
    </bean>
    <bean id="student" class="com.xsh.entity.Student">
        <constructor-arg name="name" value="小明"></constructor-arg>
        <constructor-arg name="className" value="软件一班"></constructor-arg>
        <property name="teacher" ref="teacher"></property>
        <property name="cat" ref="cat"></property>
    </bean>
    <!--    通过socpe设置bean对象时单例还是非单例:
            prototype:非单例,每次获取到的对象都是一个新的对象
            singleton:单例,容器创建好这个对象之后,每次你使用的都是同一个对象
    -->
    <bean id="test" class="com.xsh.entity.Phone" scope="prototype"></bean>
    <bean id="test1" class="com.xsh.entity.Phone" scope="singleton"></bean>
</beans>

1.3.2bean标签的属性

<!--    id:唯一标志
        class:类型
        init-method:初始化方法的执行
        destroy-method:销毁方法的执行
        scop:设置bean是否为单例,默认是单例
        lazy-init:设置bean的创建时机,默认false,
                    true:表示第一次使用该bean对象的时候才创建bean对象
                    false:表示创建spring的容器的时候就创建bean对象
-->
    <bean id="e1" class="com.xsh.entiry.ExampleBean"
          init-method="init" destroy-method="destory"
          scope="singleton" lazy-init="true"></bean>

初始化方法和销毁方法

<!-- init-method="init":创建对象的时候,执行init方法
    destroy-method="destroy:容器关闭,bean对象就调用destory方法
    默认:scope="singleleton";
-->
    <bean id="example" class="com.xsh.entity.ExampBean"
          init-method="init" destroy-method="destroy" scope="singleton"></bean>

1.3.3autowired自动装配

<!--    autowire: 自动装配,根据spring容器中的对象的id或对象的类型,按照自动装配的规则,给对象的属性初始化
                constructor:按构造器函数进行匹配
                byType:set注入,调用对应构造函数,然后根据容器中的对象类型和类的属性的类型,调用set方法,如果有多个符合条件的类型,则抛出异常
                byName:set注入,调用对应构造函数,然后根据容器中的对象id和类中的属性名,调用set方法,如果id匹配成功,但是类型不正确,则抛出异常
                **byType和byName使用的时候,对于容器中的jdk提供的类型不能自动装配
-->
    <bean id="p1" class="com.xsh.entiry.Phone" autowire="byName">
        <constructor-arg name="brand" value="华为"></constructor-arg>
    </bean>

    <bean id="brand" class="java.lang.String">
        <constructor-arg index="0" value="华为888"></constructor-arg>
    </bean>
    <bean id="price" class="java.lang.Double">
        <constructor-arg index="0" value="333.33"></constructor-arg>
    </bean>
    <bean id="mem" class="java.lang.Integer">
        <constructor-arg index="0" value="128"></constructor-arg>
    </bean>
    <bean id="phoneShell" class="com.xsh.entiry.PhoneShell">
        <property name="color" value="红色"></property>
        <property name="size" value="10"></property>
    </bean>

1.3.4补充:单例模式

单例模式是23种设计模式之一,指在程序运行时,一个类只存在一个实例对象

  • 饿汉式单例:在该类初始化的时候就创建实例对象,线程是安全的。

    //饿汉式单例
    class Hungry{
        private static final Hungry hungry = new Hungry();
    
        public Hungry getInstance(){
            return hungry;
        }
    
        private Hungry(){
        }
    }
    
  • 懒汉式单例:首次使用单例实例的时候创建,之后使用时再判断单例实例是否已创建,如果没有则创建实例,非线程安全

    //懒汉式单例
    class Lazy{
        private Lazy lazy;
        
        public Lazy getInstance(){
            if (lazy!=null){
                return new Lazy();
            }
            return lazy;
        }
    
        private Lazy(){
        }
    }
    

1.4Spring注解的使用

1.4.1开启注解使用功能

<!-- 表示支持注解的使用,如果设置了包扫描(context:component-scan),就默认开启了支持注
解的功能 -->
<context:annotation-config></context:annotation-config>

1.4.2常用注解

  • @Component : 通知spring框架,创建对象 ,默认的id,就是类名首字母小写。

  • @Configuration:在spring容器中创建对象,这个注解一般用于设置一些配置内容

  • @Bean:一般在方法前面添加这个注解,spring框架会在容器中创建这个方法返回的对象

  • @Service:业务层

  • @Controller:控制层

  • @Repository:持久层

  • @Value: 对于8种特殊数据类型和String,可以使用@Value(“xx”)的方式赋值 也可以读取属性文件的值 @Value(“${key}”)

  • @Resource (javax.annotation.Resource;) : 对于应用类型,可以采用自动装配的功能,让spring容器根据容器中的对象,根据情况赋值。

  • @Qualifier(bean的id ) : 为了避免spring容器根据类型查找的时候,出现多个匹配的类型,造成异
    常,可以使用该注解,主动设置好需要自动装配的bean的id

  • @Autowired注解,是spring框架提供的自动装配的注解。 可以byName, byType查找对象,然后自动set注入。

  • @Component(“exam”) // id ,class

  • @Scope , 设置单例,非单例

  • @Lazy ,设置懒加载

1.5AOP编程

1.5.1导入aop相关的jar包

<!-- 导入aop相关的jar包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.9.4</version>
</dependency>

1.5.1抽取公共功能封装为类

package com.xsh.dao;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

@Component
@Aspect//切面的设置
@EnableAspectJAutoProxy//开启aop的自动代理功能
public class Login1 {
//    Joinpoint 连接点 (可以理解为正在调用showTime的方法相关的对象)
    @Before("execution(public * com.xsh..*.*(..))")
    public void showTime(JoinPoint joinpoint){
        String methodName = joinpoint.getSignature().getName();//正在被执行的方法名
        Date time=new Date();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        String info = sdf.format(time);
        System.out.println(methodName+"方法开始执行:"+info);
    }

    @Around("execution(public * com.xsh.dao.*.*(..))")
    public Object exeTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long begin = System.currentTimeMillis();
        //调用正在执行的方法
        Object proceed = joinPoint.proceed();
        long end =System.currentTimeMillis();
        long cha=end-begin;
        System.out.println(joinPoint.getSignature().getName()+":执行消耗时间"+cha+"毫秒");
        return proceed;
    }

    @AfterReturning(value = "execution(public * com.xsh.dao.*.*(..))",returning = "obj")
    public void returnVal(JoinPoint joinPoint,Object obj){
//        obj表示方法的返回值
        System.out.println(joinPoint.getSignature().getName()+":"+obj);
    }
}

1.5.3AOP的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="com.xsh"></context:component-scan>
    <context:annotation-config></context:annotation-config>
    <aop:config>
        <!--        aop:切面,配置的是封装公共功能的对象-->
        <aop:aspect ref="login">
            <!--            pointcut: 切入点,通过一个表达式配置一个需要调用公共方法的类
                            execution(public * com.xsh.dao.*.*(..)):通过这个表达式,找到要调用的方法
                            第一个*:表示方法的返回值
                            com.xsh.dao.*:这个*表示所有类
                            com.xsh.dao.*.*:第二个*表示所有方法。
                            (..):表示任意参数
            -->
            <aop:pointcut id="all" expression="execution(public * com.xsh.dao.*.*(..))"/>
            <!--           before:表示前置通知,方方法执行之前,先执行前置通知对应的method
                            pointcut-ref="all":表示切入点引入all
            -->
            <aop:before method="showTime" pointcut-ref="all"></aop:before>
            <aop:around method="exeTime" pointcut-ref="all"></aop:around>
            <aop:after-returning method="returnVal"  pointcut-ref="all" returning="obj"></aop:after-returning>
        </aop:aspect>
    </aop:config>
</beans>

1.5.4AOP的注解

@Component

@Aspect // 切面的设置

@EnableAspectJAutoProxy // 开启aop的自动代理功能

2.spring mvc

2.1web项目

? java的web项目

  • servlet (extend HttpServlet) , 重写service方法

  • jsp , 显示servlet转发到jsp的数据

  • web.xml , 配置servlet的路径

  • servlet, jsp需要在容器中运行,比如: 把java web项目部署到tomcat中,启动tomcat之后,就可以访问web项目了。

    编码效率比较低:每次都需要写servlet类,然后要做配置,请求参数需要自己获取,自己封装为对应的对象

spring mvc框架的web项目
spring框架中包含了spring webmvc模块。通常把这个模块称为spring mvc框架。
MVC: mvc是一种web软件开发常使用的软件架构。
M-model : 持久层,实体类, dao , service ,统称为model.
V-View : 界面,展示数据
C-Controller :控制层, 调用业务层,转发到对应的view.

  • DispatcherServlet.java , web.xml中配置这个servlet

  • Controller(程序员写对应的类) , jsp (程序员写对应的jsp文件)

  • ViewResolver & jsp , (jsp的路径配置 , spring.xml配置文件做配置)

  • HandlerMapping (java的Controller类型, 映射为url , spring.xm配置文件中配置),可以用注解简化配置:HandlerMapping

2.2spring mvc的使用

  • 导入对应的jar包

    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.21</version>
    </dependency>
    
  • 配置web.xml文件

    <!-- 1. tomcat容器启动的时候,就初始化DispatcherServlet
    2. DispatcherServlet创建对象的时候,就会创建spring的容器对象。
    -->
    <servlet>
    <servlet-name>mvc</servlet-name>
    <servletclass>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 通过servlet的初始化参数的配置,指定spring的配置文件的路径-->
    <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:springmvc1.xml</param-value>
    </init-param>
    <!-- tomcat容器启动的时候,就初始化对象-->
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>mvc</servlet-name>
    <!-- **DispatcherServlet的路径只能用通配路径 -->
    <url-pattern>/</url-pattern>
    </servlet-mapping>
    
  • controller

    package com.xsh.controller;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.Map;
    public class FirstController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request ,
    HttpServletResponse response) throws Exception {
    ModelAndView mav = new ModelAndView(); // 自己创建
    Map<String, Object> model = mav.getModel(); // 获取到一个map, 把需要转
    发到jsp页面的数据,保存在这个map中
    model.put("name" , "小红");
    mav.setViewName("Hello"); // 设置要转发的jsp的名字
    return mav;
    }
    }
    
  • jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
    <title>Title</title>
    </head>
    <body>
    ${name} , 欢迎使用!
    </body>
    </html>
    
  • ViewResolver、HandlerMapping

    <bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!-- suffix: 后缀
    prefix:前缀
    通过contrller中转发的view的名字, 和这里前缀,后缀做拼接,然后得到jsp页面
    的路径。
    比如: /WEB-INF/ + Hello + .jsp , 这个就是jsp的路径。
    -->
    <property name="suffix" value=".jsp"></property>
    <property name="prefix" value="/WEB-INF/"></property>
    </bean>
    <!-- bean的配置-->
    <bean id="ft" class="com.xsh.controller.FirstController"></bean>
    <bean id="sc" class="com.xsh.controller.SecondController"></bean>
    <!-- Controller对应的请求路径的配置-->
    <bean id="handlerMapping"
    class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
    <props>
    <!-- 属性的key 就是请求的url地址, value就是url地址对应要找的
    Controller的bean的id .-->
    <prop key="first">ft</prop>
    <prop key="second">sc</prop>
    </props>
    </property>
    </bean>
    

2.3spring mvc注解的使用

  • spring.xml支持springmvc注解的设置

    <!-- mvc的注解驱动-->
    <mvc:annotation-driven></mvc:annotation-driven>
    <!-- 组件扫描-->
    <context:component-scan base-package="com.xsh.controller">
    </context:component-scan>
    <bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!-- suffix: 后缀
    prefix:前缀
    通过contrller中转发的view的名字, 和这里前缀,后缀做拼接,然后得
    到jsp页面的路径。
    比如: /WEB-INF/ + Hello + .jsp , 这个就是jsp的路径。
    -->
    <property name="suffix" value=".jsp"></property>
    <property name="prefix" value="/WEB-INF/"></property>
    </bean>
    
  • Controller中的注解

@GetMapping("/add") // 请求的访问方式的限定 , 只支持get
public String add(){
System.out.println("getMapping......");
return "success";
}
@PostMapping("/add")// 请求的访问方式的限定 , 只支持post
public String add1(){
System.out.println("postMapping.....");
return "success";
}
@RequestMapping("/add") // 省略了value属性
public String add2(){
System.out.println("requestMapping .....");
return "success";
}

2.4将controller中的数据转发到jsp

  • Model

    @RequestMapping("/query")
    public String query( Model model , Integer eno ,
    HttpServletRequest request){
    Emp emp = new Emp();
    emp.setEName("小红");
    // model中的数据会转发到jsp页面上
    model.addAttribute("emp" , emp);
    return "success";
    }
    
  • ModelMap

    @RequestMapping("/query1")
    public String query1(ModelMap modelMap , Integer eno){
    Emp emp = new Emp();
    emp.setEName("小红");
    // modelMap中的数据会转发到jsp页面上
    modelMap.put("emp" , emp);
    return "success";
    }
    
  • ModelAndView

    @RequestMapping("/query2")
    public ModelAndView query2(Integer eno){
    Emp emp = new Emp();
    emp.setEName("小红");
    ModelAndView mav = new ModelAndView();
    ModelMap modelMap = mav.getModelMap();
    modelMap.put("emp" , emp);
    mav.setViewName("success");
    return mav;
    }
    

2.5拦截器的使用

2.5.1定义拦截器

implements HandlerInterceptor , 重写方法

package com.xsh.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginInterceptor implements HandlerInterceptor {
@Override
// preHandle方法。当发起请求的时候,就会进入到拦截器中的preHanle方法的运行。
// 如果preHandle方法返回值是true,表示不被拦截,继续访问请求。 返回false,表示被拦截
了, 不能访问请求了。
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
System.out.println("进入拦截器了:preHandle。。。。。。。。。");
HttpSession session = request.getSession();
Object loginuser = session.getAttribute("loginuser");
if(loginuser == null){// 没有登陆过
response.sendRedirect(
request.getContextPath() +"/toLogin"); // 重定向到登陆界面
return false;
}else{//登陆过
return true;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle............");
}
}

2.5.2拦截器的配置

  • xml中配置

    拦截的路径有哪些

    不拦截的路径要设置例外

    <mvc:interceptors>
    <!-- 拦截器的配置-->
    <mvc:interceptor>
    <!-- 表示,所有的路径都要被拦截-->
    <mvc:mapping path="/**"/>
    <!-- exclude: 例外 , 表示那些请求不被拦截-->
    <mvc:exclude-mapping path="/toLogin"/>
    <mvc:exclude-mapping path="/login"/>
    <!-- 静态资源不被拦截-->
    <mvc:exclude-mapping path="/js/**"/>
    <mvc:exclude-mapping path="/html/**"/>
    <!-- 拦截器对应的类型-->
    <bean class="com.xsh.interceptor.LoginInterceptor"></bean>
    </mvc:interceptor>
    <mvc:interceptor>
    <!-- 表示只拦截/emp/** -->
    <mvc:mapping path="/emp/**"/>
    <bean class="com.xsh.interceptor.RoleInterceptor"></bean>
    </mvc:interceptor>
    </mvc:interceptors>
    
  • java类中添加拦截器

    要求:在spring mvc的配置文件中不能出现mvc:annotation-driven标签

    @Configuration // 配置文件的注解
    @EnableWebMvc // 替代配置文件中的:<mvc:annotation-driven></mvc:annotationdriven>
    public class MVCConfig implements WebMvcConfigurer {
    @Override // 拦截器的设置
    public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LoginInterceptor())
    .addPathPatterns("/**")
    .excludePathPatterns("/toLogin")
    .excludePathPatterns("/login")
    .excludePathPatterns("/js/**")
    .excludePathPatterns("/html/**");
    registry.addInterceptor(new RoleInterceptor())
    .addPathPatterns("/emp/**");
    }
    }
    

2.6异常处理

2.6.1局部异常处理

// 局部异常处理方式
/*
@ExceptionHandler// 表示如果EmpController内部的请求发生异常,就执行这里toException
方法。
public String toException(Exception e){
e.printStackTrace(); // 打印异常的堆栈信息
System.out.println(e.getCause());
return "part"; // 如果请求中发生异常,就转发到part.jsp
}
*/
@ExceptionHandler(NullPointerException.class) // 表示如果EmpController内部的
请求发生异常,就执行这里toException方法。
public String toException(Exception e){
e.printStackTrace(); // 打印异常的堆栈信息
System.out.println(e.getCause());
5.2全局异常处理
return "part"; // 如果请求中发生异常,就转发到part.jsp
}

2.6.2全局异常处理

// 通过注解设置为全局异常处理的类
@ControllerAdvice // Controller 控制器 , Advice 通知
public class GlobalExceptionHandler {
@ExceptionHandler
public String toException(Exception e){
e.printStackTrace();
return "global";// 找global.jsp
}
}

3.Mybatis

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几

乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置

和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式Java 对象)为数据库中的记录。

mybatis是一个数据库相关的框架,主要为了简化jdbc的操作

mybatis使用了orm,ORM是对象关系映射的英文缩写,ORM是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。

3.1mybatis的使用步骤

3.1.1mybatis的jar包

数据库jar包, mybatisjar包

<dependency>
><groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!--	mybatis的包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId
<version>3.5.10</version>
</dependency>

3.1.2mybatis的核心配置文件

  • 数据库连接的环境配置

  • 日志输出的配置

  • 需要加载的mapper.xml文件的配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 设置控制台日志输出-->
<!-- 配置数据库连接的环境 : 默认使用id为"development"的环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/gamedb?serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 引用存在的mapper.xml文件-->
<mappers>
<mapper resource="mapper/HeroMapper.xml"/>
</mappers>
</configuration>

3.1.3实体类和接口

  • Hero.java
package com.xsh.entity;

import lombok.Data;

import lombok.ToString;

import java.util.Date;

// 属性名和table-hero的字段名完全一样。
@Data

@ToString

public class Hero {

private Integer id;

private String name;

private String sex;

private String position;

private Integer price;

private Date shelf_date;

}
  • HeroDao.java
package com.xsh.dao;
import com.xsh.entity.Hero;
import java.util.List;
// 定义数据库操作的方法
public interface HeroDao {
public abstract int addHero(Hero hero);
public abstract int deleteHero(Integer id);
public abstract int updateHero(Hero hero);
public abstract List<Hero> queryAll();
}

3.1.4 mapper.xml的配置

  • 在resource目录中创建一个文件夹mapper。 专门用于存放mapper.xml

  • 在mybatis-config.xml中引用mapper.xml

<mappers>
<mapper resource="mapper/HeroMapper.xml"/>
</mappers>
  • EntityDaoMapper.xml
<mappers>

<mapper resource="mapper/HeroMapper.xml"/>

</mappers>

<?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">

<!-- namespace: 命名空间 , 设置mapper.xml文件中的sql 对应的 interface。 -->

<mapper namespace="com.xsh.dao.HeroDao">

<!-- insert:表示这是一个插入的sql语句

id: 对应dao(interface)中方法的名字

parameterType: 设置的dao(interface)中方法的参数

insert标签的内部: sql语句

sql语句中的#{属性名} , 就是在获取参数对象的属性的值 -->

<insert id="addHero" parameterType="com.xsh.entity.Hero">

insert into hero values(null, #{name} , #{sex}

, #{position} , #{price} , #{shelf_date})

</insert>

<!-- 方法的参数是一个,并且属于8种类型 ,就可以省略。

也可以设置parameterType="int" ,这里的int就是简写

\#{id} ,这里的id和方法参数名完全一致, deleteHero(Integer id)-->

<delete id="deleteHero">

delete from hero where id = #{id}

</delete>

<!-- price=#{price} , price是列名(table的列名),

\#{price}(实体类的属性) ,这里是属性值的获取。-->

<update id="updateHero" parameterType="com.xsh.entity.Hero">

update hero set `name` = #{name} , sex=#{sex},

`position` =#{position } , price=#{price} ,

shelf_date=#{shelf_date} where id=#{id}

</update>

<!-- resultType="com.xsh.entity.Hero":返回值是一个实体,或者泛型为实体的集

合,

设置的返回值类型都是这个实体类。-->

<select id="queryAll" resultType="com.xsh.entity.Hero">

select * from hero

</select>
</mapper>

3.1.5测试mybatis的功能

package com.xsh;
import com.xsh.dao.HeroDao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
public class AppTest
{
SqlSession sqlSession;
// HeroDao --> SqlSession --> SqlSessionFactory ---> io(mybatisconfig.xml)
@Before
public void createSession() throws Exception{
String location = "mybatis-config.xml"; // mybatis配置文件的路径
InputStream resourceAsStream =
Resources.getResourceAsStream(location);
// 创建session工厂类
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(resourceAsStream);
// 获取session对象
sqlSession = sqlSessionFactory.openSession();
}
@After
public void closeAndCommit(){
sqlSession.commit(); // 提交 (更新必须提交 ,不然数据库并不会写入)
sqlSession.close();
}
@Test
public void testQuery()
{
HeroDao dao = sqlSession.getMapper(HeroDao.class);
// ---- 编译的时候是引用类型 , 运行的时候是实际类型
System.out.println("dao:" + dao.getClass());
dao.queryAll();
}
}

3.2ResultMap的使用

如果实体类的属性和表的字段名不一致,可以使用resultMap 设置实体类的属性和表的字段的对应关
系。

GoodsInfo.java

@Data
@ToString
public class GoodsInfo {
// 采用驼峰命名法
private Integer giId;
private Integer gtId;
private String giName;
private Double giPrice;
private Integer giNum;
private String giNote;
private String giImg;
}

GoodsInfoDao.java

public List<GoodsInfo> queryAll();

GoodsInfoMapper.xml

<!-- 自定义resultMap类型, 通过id,引用这个类型。-->
<resultMap id="GIMap" type="com.xsh.entity.GoodsInfo">
<id column="gi_id" property="giId"></id>
<result column="gt_id" property="gtId" javaType="java.lang.Integer">
</result>
<result column="gi_name" property="giName"></result>
<result column="gi_price" property="giPrice"></result>
<result column="gi_num" property="giNum"></result>
<result column="gi_note" property="giNote"></result>
<result column="gi_img" property="giImg"></result>
</resultMap>
<!-- 返回值类型设置为resultMap ,引用定义好的resultMap。-->
<select id="queryAll" resultMap="GIMap">
select * from goods_info
</select>

3.3接口方法的定义

接口方法的返回值

// dao中的方法的返回值的情况: void ,int(Integer) --- insert, delete , update
// 实体类,实体类的集合 --- select
// Map , List<Map> --- select
// int(统计行数) ---- select

public List<GoodsInfo> queryAll();
public GoodsInfo queryByID(Integer giId);
public Map<String , Object> queryByIDMap(Integer giId);
public int queryTotal(); // 统计总函数 count(*)
public List<Map<String ,Object>> queryByGroup();
public List<GroupGoods> queryByGroupGoods();
public void addGoodsInfo(GoodsInfo info);

xml

<!-- 自定义resultMap类型, 通过id,引用这个类型。-->
<resultMap id="GIMap" type="com.xsh.entity.GoodsInfo">
<id column="gi_id" property="giId"></id>
<result column="gt_id" property="gtId" javaType="java.lang.Integer">
</result>
<result column="gi_name" property="giName"></result>
<result column="gi_price" property="giPrice"></result>
<result column="gi_num" property="giNum"></result>
<result column="gi_note" property="giNote"></result>
<result column="gi_img" property="giImg"></result>
</resultMap>
<!-- public List<GoodsInfo> queryAll();
public GoodsInfo queryByID(Integer giId);-->
<select id="queryAll" resultMap="GIMap">
select * from goods_info
</select>
<select id="queryByID" resultMap="GIMap" parameterType="int">
select gi_name , gi_price , gi_num
from goods_info where gi_id= #{giId}
</select>
<!-- public int queryTotal(); // 统计总函数 count(*)-->
<select id="queryTotal" resultType="java.lang.Integer">
select count(*) from goods_info
</select>
<!-- public Map<String , Object> queryByIDMap(Integer giId);-->
<select id="queryByIDMap" resultType="map">
select gi_name , gi_price , gi_num
from goods_info where gi_id= #{giId}
</select>
2.2接口方法的参数
java
xml
<!-- public List<Map<String ,Object>> queryByGroup();-->
<select id="queryByGroup" resultType="java.util.Map">
SELECT count(goods_info.gt_id) as count , SUM(gi_num) as total
, goods_info.gt_id as type,gt_name as name from goods_info , goods_type
where goods_info.gt_id = goods_type.gt_id
GROUP BY goods_info.gt_id
</select>
<!-- public List<GroupGoods> queryByGroupGoods();-->
<select id="queryByGroupGoods" resultType="com.xsh.entity.GroupGoods">
SELECT count(goods_info.gt_id) as count , SUM(gi_num) as total
, goods_info.gt_id as type,gt_name as name from goods_info , goods_type
where goods_info.gt_id = goods_type.gt_id
GROUP BY goods_info.gt_id
</select>
<!-- public void addGoodsInfo(GoodsInfo info);
*** 希望把插入成功之后的主键值,保存在GoodsInfo对象中,这个案列,就会保存在参数info
中。
suseGeneratedKey="true" keyColumn="gi_id" keyProperty="giId"
-->
<insert id="addGoodsInfo" parameterType="com.xsh.entity.GoodsInfo"
useGeneratedKeys="true" keyColumn="gi_id" keyProperty="giId">
insert into goods_info(gi_id , gt_id , gi_name , gi_price , gi_num ,
gi_note , gi_img)
values(null , #{gtId} , #{giName} , #{giPrice} ,#{giNum} , #{giNote} ,#
{giImg})
</insert>

接口方法的参数

// dao中方法的参数的情况:
// 插入(insert) , 更新(update) --- 实体类 , map ,一个参数(8中类型,String)
// ----多个参数 addGoodsInfo(Integer gi_id , String gi_name , Double
gi_price ......);
// 删除(delete) --- integer(主键) , map(多个条件) ,一个参数(8中类型,
String// 查询(select) --- 实体类, map , 多个参数,一个参数(8中类型,String)
public void updateByWhere(Map map) ; // map添加几个key ,在sql语句中使用 #{key}
获取value值
// 如果方法参数超过一个 ,就需要在参数前添加@Param注解,给参数重命名,在sql
// 语句中规定,通过#{param注解重命名的key}获取参数值
public List<GoodsInfo> selectWhere(@Param("gid") Integer id ,
@Param("type") Integer type ,@Param("jiage") Double price );
// select * from goods_info where gi_id>#{gid} and gt_id=#{type}
// and gi_price<#{jiage}
public void delete(Integer giId);

xml

<!-- public void updateByWhere(Map map) -->
<update id="updateByWhere" parameterType="map">
update goods_info set
gi_num=#{num} where gt_id=#{type}
</update>
<!-- public List<GoodsInfo> selectWhere(@Param("gid") Integer id ,
@Param("type") Integer type ,@Param("jiage") Double price );
-->
<select id="selectWhere" resultMap="GIMap" >
select * from goods_info where gi_id>#{gid} and gt_id=#{type}
and gi_price &lt; #{jiage}
</select>
<delete id="delete" >
delete from goods_info where gi_id=#{giId}
</delete>

3.4动态sql语句

使用一些标签,实现sql语句可以根据条件,拼出不同的sql语句,实现不同的功能。

  • if: 判断是否需要添加sql语句段

  • where:拼where关键字

  • set:拼set关键字

  • trim: 对where 和set可以进行简化

    java

    ublic interface DynamicGoodsInfoDao {
    // 根据参数是否为空,动态完成sql语句的拼接
    public List<GoodsInfo> findWhere(GoodsInfo info);
    // 根据参数是否为空,动态完成sql语句的拼接
    public List<GoodsInfo> findWhereTwo(GoodsInfo info);
    public void updateSelectiveById(GoodsInfo info);
    public void updateSelectiveByIdTrim(GoodsInfo info);
    }
    

    xml

<!-- public void updateByWhere(Map map) -->
<update id="updateByWhere" parameterType="map">
update goods_info set
gi_num=#{num} where gt_id=#{type}
</update>
<!-- public List<GoodsInfo> selectWhere(@Param("gid") Integer id ,
@Param("type") Integer type ,@Param("jiage") Double price );
-->
<select id="selectWhere" resultMap="GIMap" >
select * from goods_info where gi_id>#{gid} and gt_id=#{type}
and gi_price &lt; #{jiage}
</select>
<delete id="delete" >
delete from goods_info where gi_id=#{giId}
</delete>
public interface DynamicGoodsInfoDao {
// 根据参数是否为空,动态完成sql语句的拼接
public List<GoodsInfo> findWhere(GoodsInfo info);
// 根据参数是否为空,动态完成sql语句的拼接
public List<GoodsInfo> findWhereTwo(GoodsInfo info);
public void updateSelectiveById(GoodsInfo info);
public void updateSelectiveByIdTrim(GoodsInfo info);
}
<?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">
<!-- namespace: 命名空间 , 设置mapper.xml文件中的sql 对应的 interface。 -->
<mapper namespace="com.xsh.dao.DynamicGoodsInfoDao">
<!-- 自定义resultMap类型, 通过id,引用这个类型。-->
<resultMap id="GIMap" type="com.xsh.entity.GoodsInfo">
<id column="gi_id" property="giId"></id>
<result column="gt_id" property="gtId" javaType="java.lang.Integer">
</result>
<result column="gi_name" property="giName"></result>
<result column="gi_price" property="giPrice"></result>
<result column="gi_num" property="giNum"></result>
<result column="gi_note" property="giNote"></result>
<result column="gi_img" property="giImg"></result>
</resultMap>
<!-- 使用if标签, 判断传入的参数值,如果参数值不是null,则拼对应的sql语句-->
<select id="findWhere" resultMap="GIMap"
parameterType="com.xsh.entity.GoodsInfo">
select * from goods_info where 1=1
<if test="giId!=null">
and gi_id = #{giId}
</if>
<if test="gtId!=null">
and gt_id = #{gtId}
</if>
<if test="giPrice!=null">
and gi_price>#{giPrice}
</if>
<if test="giNum!=null">
and gi_num > #{giNum}
</if>
</select>
<!-- 使用where标签, 然后where标签会自动添加where关键字,并且可以去掉多于的and 。-->
<select id="findWhereTwo" resultMap="GIMap"
parameterType="com.xsh.entity.GoodsInfo">
select * from goods_info
<where>
<if test="giId!=null">
and gi_id = #{giId}
</if>
<if test="gtId!=null">
and gt_id = #{gtId}
</if>
<if test="giPrice!=null">
and gi_price>#{giPrice}
</if>
<if test="giNum!=null">
and gi_num > #{giNum}
</if>
</where>
</select>
<!-- public void updateSelectiveById(GoodsInfo info);
set标签,会添加set关键字,并且去掉多于的逗号 ,如果传入的参数的属性都是null,
那么抛异常-->
<update id="updateSelectiveById"
parameterType="com.xsh.entity.GoodsInfo">
update goods_info
<set>
<if test="gtId!=null">
gt_id=#{gtId} ,
</if>
<if test="giName!=null">
gi_name=#{giName} ,
</if>
<if test="giPrice!=null">
gi_price=#{giPrice} ,
</if>
<if test="giNum!=null">
gi_num=#{giNum} ,
</if>
<if test="giNote!=null">
gi_note=#{giNote} ,
</if>
<if test="giImg!=null">
gi_img=#{giImg} ,
</if>
</set>
<where>
<if test="giId!=null">
gi_id=#{giId}
</if>
</where>
</update>
<!-- public void updateSelectiveByIdTrim(GoodsInfo info);
trim标签:可以通过前缀,后缀等设置,替代where,set等标签。
prefix="" ,前面添加什么内容
prefixOverrides="" ,把前面多于的什么内容给去掉,
suffix="" 后面添加什么内容
suffixOverrides="" , 把后面多于的什么内容给去掉
-->
<update id="updateSelectiveByIdTrim"
parameterType="com.xsh.entity.GoodsInfo">
update goods_info
<trim prefix="set" prefixOverrides="" suffix=" where gi_id=#{giId}"
suffixOverrides=",">
<if test="gtId!=null">
gt_id=#{gtId} ,
</if>
<if test="giName!=null">
gi_name=#{giName} ,
</if>
<if test="giPrice!=null">
gi_price=#{giPrice} ,
</if>
<if test="giNum!=null">
gi_num=#{giNum} ,
</if>
<if test="giNote!=null">
gi_note=#{giNote} ,
</if>
<if test="giImg!=null">
gi_img=#{giImg} ,
</if>
</trim>
</update>
</mapper>

3.5关联查询

BookInfo.java

// 两个表的关联查询: 查询书的时候,查出书的类型相关信息
// 一本书对应一个类型
@Data
@ToString
public class BookInfo {
// id -- 主键
private Integer bookId;
// result --- 普通的列
private Integer typeId;
private String bookName;
private String bookAuthor;
private Double bookPrice;
private Date bookPublishDate;
private Integer bookNum;
// 书的类型信息
// -- 关联的对象
private BookType bookType ;
}

BookType.java

// 两个表的关联查询 : 查询书的类型的时候,就查询出该类型下的所有书。
// 一对多:一个类型下有多个书
@Data
@ToString
public class BookType {
private Integer typeId;
private String typeName;
// 属于某个类型中的所有书
private List<BookInfo> bookInfoList;
}

mapper.java

public interface BookInfoDao {
public List<BookInfo> queryAll();
}

mapper.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">
<!-- namespace: 命名空间 , 设置mapper.xml文件中的sql 对应的 interface-->
<mapper namespace="com.xsh.dao.BookInfoDao">
<resultMap id="BookInfoMap" type="com.xsh.entity.BookInfo">
<id property="bookId" column="book_id"></id>
<result property="typeId" column="type_id"></result>
<result property="bookName" column="book_name"></result>
<result property="bookAuthor" column="book_author"></result>
<result property="bookPrice" column="book_price"></result>
<result property="bookPublishDate" column="book_publish_date"></result>
<result property="bookNum" column="book_num"></result>
<!-- association : 设置关联关系对应的属性
property="bookType" : 有关联关系的属性名
javaType="com.xsh.entity.BookType" :有关联关系的属性对应的类型
-->
<association property="bookType" javaType="com.xsh.entity.BookType">
<id property="typeId" column="type_id"></id>
<result property="typeName" column="typeName"></result>
</association>
</resultMap>
<!-- public List<BookInfo> queryAll();-->
<select id="queryAll" resultMap="BookInfoMap" >
select * from bookinfo as info , book_type as type where
info.type_id = type.type_id
</select>
</mapper>

3.6分页插件的使用

  • 导入分页插件相关的jar包
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
  • 在mybatis-config.xml中配置分页的插件
<!-- 分页插件的配置-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 分页参数不对的时候, page <1 , 设置显示第一页的内容,
page > maxPage , 显示最后一页的内容-->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
  • 测试分页的功能
@Test
public void testPageHelper(){
BookInfoDao dao = sqlSession.getMapper(BookInfoDao.class);
// 查询之前,设置要查询的页面和要查询的条数
// PageHelper.startPage(页码, 几行)
PageHelper.startPage(2, 1) ;//
List<BookInfo> bookInfos = dao.queryAll();
// 把跟分页相关的所有信息,保存在pageInfo对象中。
PageInfo<BookInfo> pageInfo = new PageInfo<>(bookInfos); // 必须把
dao.queryAll();的结果作为参数传给PageInfo对象
//System.out.println(pageInfo);
// System.out.println(pageInfo.getPages());
// System.out.println(pageInfo.getList());
System.out.println(pageInfo.getList().get(0));
}

4.ssm整合

4.1依赖包

  • mybatis.jar

  • spring mvc.jar

  • mysql.jar

  • mybatis-spring.jar

  • junit-4.12.jar

  • c3p0.jar (数据源)

  • servlet-api.jar , jstl.jar, standard.jar

  • spring-tx.jar , spring-jdbc.jar

  • 其他

4.2配置

  • web.xml

  • Spring-mvc.xml

  • mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    <!-- 设置控制台日志输出-->
    <settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!-- 分页插件的配置-->
    <plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
    <!-- 分页参数不对的时候, page <1 , 设置显示第一页的内容,
    page > maxPage , 显示最后一页的内容-->
    <property name="reasonable" value="true"/>
    </plugin>
    </plugins>
    </configuration>
    
  • mydb.properties

  • ssm整合的配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/mvc
    https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <context:property-placeholder location="classpath:mydb.properties">
    </context:property-placeholder>
    <!-- bean的配置-->
    <bean id="sqlSessionFactory"
    class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="ds"></property>
    <property name="configLocation" value="classpath:mybatisconfig.xml"></property>
    <!-- 指定mapper.xml的路径-->
    <property name="mapperLocations" value="classpath:mapper/*.xml">
    </property>
    </bean>
    <!-- 数据源对应的bean的配置-->
    <bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="password" value="${mydb.pwd}"></property>
    <property name="user" value="${mydb.user}"></property>
    <property name="jdbcUrl" value="${mydb.url}"></property>
    <property name="driverClass" value="${mydb.driver}"></property>
    </bean>
    <!-- mapper.java的扫描配置
    *** spring框架的容器中可以找到mapper.java的实现类对象。程序员通过自动装配,就
    比较方便的使用这些mapper.java
    -->
    <bean id="mapperScanner"
    class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- set注入:设置mapper.java所在的package-->
    <property name="basePackage" value="com.xsh.ssm.dao"></property>
    <!-- set注入: 指定sqlSessionFactoryBean-->
    <property name="sqlSessionFactoryBeanName"
    value="sqlSessionFactory"></property>
    </bean>
    </beans>
    

4.3ssm+ajax

json转换的jar包

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.11</version>
</dependency>

spring.xml配置转换器

<mvc:annotation-driven>
<mvc:message-converters>
<bean
class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=utf-8</value>
<value>application/json;charset=utf-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

controller中的使用

@RestController // 类中所有的请求的返回值都会被转换为json格式。(Map , List<T> , 实
体类, Object@RequestMapping("/emp")
@CrossOrigin(value = "http://127.0.0.1:8848/")// 允许被跨域访问
public class EmpController {
@Autowired
EmpService service ;
@RequestMapping("/list")
public Map<String , Object> queryOnePage(@RequestParam(defaultValue =
"1") Integer page ,
@RequestParam(defaultValue = "3") Integer
limit){
PageInfo<Emp> pageInfo = service.queryByPage(page, limit);
Map<String , Object> map = new HashMap<>();
4. 页面上的使用
使用jquery的ajax函数,发送异步请求:
5. 安装postman ,可以测试请求
map.put("count" , pageInfo.getTotal()); //pageInfo.getTotal()-- 总行
数
map.put("code" , 0) ;
map.put("msg" ,"");
map.put("data" ,pageInfo.getList() ); //pageInfo.getList() --当前页的
数据
return map;
}
@RequestMapping("/add")
public Map<String ,Object> addEmp(Emp emp){
Boolean aBoolean = service.addEmp(emp);
Map<String , Object> map = new HashMap<>();
map.put("success" , aBoolean);
return map;
}
@RequestMapping("/one")
public Emp queryByEno(Integer eno){
return service.queryByEno(eno);
}
}

jquery使用ajax

$.ajax({
url:"http://localhost:8080/ssm_ajax/emp/add", // 请求地址
data: data.field, // 提交请求的表单的数据
type:"post", // 请求方式
dataType:"json", // 期待的返回值类型
success:function(res){ // res就是响应结果
if(res.success){
layer.msg("添加成功"); // layer.msg-- 弹出一个信息
}else{
layer.msg("添加失败")
}
}
})

5.springboot+mybatis plus

5.1导入mybatis plus的jar包

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>

5.2使用mybatis plus自动生成

5.2.1导入需要的bao

<!-- mybatis plus 自动生成-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.3</version>
</dependency>
<!-- freemarker的包-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
<!-- swagger的包-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>

5.2.2配置运行自动生成的main函数

public class GenMyBatisPlus {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/empdb?
serverTimezone=Asia/Shanghai",
"root", "123456")
.globalConfig(builder -> {
builder.author("fengjm") // 设置作者
.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir("D:/javaweb/sbmp/src/main/java"); // 指定输
出目录
})
3.3测试功能
4. mybatis plus的分页查询
分页的拦截器的配置
测试分页的功能
.packageConfig(builder -> {
builder.parent("com.xsh.sbmp") // 设置父包名
// .moduleName("emp") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.xml,
"D://")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("emp" ,"user" , "dept") // 设置需要生成的表名
.addTablePrefix("t_", "c_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker
引擎模板,默认的是Velocity引擎模板
.execute();
}
}

5.2.3使用

@SpringBootTest
class SbmpApplicationTests {
@Autowired
IEmpService service ;
@Test
public void testSelect(){
Emp byId = service.getById(3);
// System.out.println(byId.getEname());
System.out.println(byId.getEname());
}
}

5.3分页查询

配置分页拦截器的类

@Configuration
public class PageConfig {
@Bean // set注入 mybatis plus 分页插件
public MybatisPlusInterceptor pageAdd(){
MybatisPlusInterceptor interceptor =
new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(
new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor ;
}
}

使用分页

@Test
public void testSelect(){
Page<Emp> page =
service.page(new Page<>(1, 5));
List<Emp> records = page.getRecords();
System.out.println(records);
}

5.4条件查询

// 等于和and的查询 : 把传给QueryWrapper的实体类对象的非空属性值,用“等于”进行条件拼接 ,多
个条件用and 连接。
// -- SELECT eno,ename,ejob,emanager,ehiredate,esalary,deptno,emp_img FROM
emp
// WHERE ejob=? AND emanager=?
@Test
public void query(){
Emp emp = new Emp();
emp.setEjob("yyyy");
emp.setEmanager(1);
QueryWrapper<Emp> empQueryWrapper = new QueryWrapper<>(emp);
List<Emp> list = service.list(empQueryWrapper);
System.out.println(list);
}
// 用QueryWrapper , 拼接各种复杂的条件
// 比如: eq , like gt , lt , in....
// 比如: apply拼sql语句段
// 比如:or , 拼"或"的条件
// 比如: orderByAsc , orderByDesc
//SELECT eno,ename,ejob,emanager,ehiredate,esalary,deptno,emp_img FROM emp
// WHERE (esalary > ? OR eno < ? AND ename LIKE ? AND deptno=1) ORDER BY esalary
DESC
@Test
public void query1(){
QueryWrapper<Emp> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("esalary" , 3000.0); //gt是大于 第一个参数是列名,第二个参数是
数据,
queryWrapper.or().lt("eno" , 10);//lt小于
queryWrapper.like("ename" , "%y%");// like.像.....
queryWrapper.apply(" deptno=1");
queryWrapper.orderByDesc("esalary");
List<Emp> list = service.list(queryWrapper);
}
@Test // SELECT ename ,ejob FROM emp WHERE (esalary > ?)
public void query2(){
QueryWrapper<Emp> queryWrapper = new QueryWrapper<>();
queryWrapper.select("ename " , "ejob").gt("esalary" , 3000.0);
List<Map<String, Object>> maps = service.listMaps(queryWrapper);
System.out.println(maps);
}

5.5swagger3的使用

jar包

<!-- swagger的包-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>

添加注解

  • controller

    @RestController
    @RequestMapping("/emp")
    @Api(tags = "员工管理模块")
    public class EmpController {
    @Autowired
    IEmpService iEmpService ;
    // 查询一页的请求
    @RequestMapping(value = "/page" , method = RequestMethod.POST)
    @ApiOperation(value = "分页查询" , notes = "当前页码的员工们")
    public List<Emp> selectPage(@ApiParam(value = "页码" , required = true)
    @RequestParam(defaultValue = "1") int
    page,
    @ApiParam(value = "每页显示的行数" )
    @RequestParam(defaultValue = "3") int
    limit){
    Page<Emp> page1 = iEmpService.page(new Page<>(page, limit));
    return page1.getRecords(); // 获取到当前页的数据
    }
    }
    
  • 实体类

    @ApiModel(value = "Emp对象", description = "")
    public class Emp implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("员工编号")
    @TableId(value = "eno", type = IdType.AUTO)
    private Integer eno;
    @ApiModelProperty("员工名字")
    private String ename;
    @ApiModelProperty("工作岗位")
    private String ejob;
    @ApiModelProperty("部门经理")
    private Integer emanager;
    @ApiModelProperty("入职日期")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" , timezone = "GMT+8")
    private LocalDateTime ehiredate;
    @ApiModelProperty("工资")
    private BigDecimal esalary;
    @ApiModelProperty("部门编号")
    private Integer deptno;
    @ApiModelProperty("员工照片的地址")
    private String empImg;
    // code .......
    }
    

启动springboot项目,访问http://localhost:8080/swagger-ui/

单独配置swagger3的类

@Configuration
@EnableOpenApi
public class Swagger3Config {
/**
* ture 启用Swagger3.0, false 禁用(生产环境要禁用)
*/
Boolean swaggerEnabled=true;
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
// 是否开启
.enable(swaggerEnabled)
.select()
// 扫描的路径使用@Api的controller
//.apis(RequestHandlerSelectors.withMethodAnnotation(Api.class))
.apis(RequestHandlerSelectors.basePackage("com.hqyj.sbmp.controller"))
// 指定路径处理PathSelectors.any()代表所有的路径
.paths(PathSelectors.any())
.build();
}
6. mybatis plus的条件查询
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("员工管理系统")
.description("员工管理系统接口说明文档")
//作者信息
.contact(new Contact("alice","https://xxxx.icu/",
"alice@qq.com"))
.version("1.0")
.build();
}
}

6.springboot+jpa

6.1概念

JPA(java persistence api),是java提供的访问数据库的规范,Hibernate是完全实现了jpa,spring对hibernate实现的jpa进行了封装,提供了spring data jpa,使用spring data jpa的包,实现数据库访问。

sql和hql:

sql:查询的数据库,select * from emp

hql:查询的对象,from emp

6.2使用步骤

  • spring boot 项目的创建

  • spring data jpa包的导入

在pom.xml中导入依赖(idea会自动导入)

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
  • 数据库的连接

在application.xml中配置连接数据库的信息

#连接数据库的信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shopdb?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
#配置数据库
spring.jpa.database=mysql
#配置数据库方言
#spring.jpa.properties.
#显示sql
spring.jpa.show-sql=true
#spring.jpa.open-in-view=false
  • 建立实体类&table的关系

entity.java

package com.xsh.sbjpa.entity;

import lombok.Data;
import lombok.ToString;

import javax.persistence.*;

@Data
@ToString
@Entity//表示为一个实体类,让jpa中能找得到它,可以对数据库进行增删改查的操作
@Table(name = "goods_info")//设置表名
public class GoodsInfo {
    @Id//表示主键
    //根据table的主键的要求,确定是否要设置主键增长策略
    @GeneratedValue(strategy= GenerationType.IDENTITY)//策略,GenerationType.IDENTITY--对应MySQL的自动增长
    @Column(name="gi_id")//设置属性对应的字段
    private Integer giId;
    @Column(name="gt_id")
    private Integer gtId;
    @Column(name="gi_name")
    private String giName;
    @Column(name="gi_price")
    private Double giPrice;
    @Column(name="gi_num")
    private Integer giNum;
    @Column(name="gi_note")
    private String giNote;
    @Column(name="gi_img")
    private Integer giImg;
}

idea中连接数据库来消除报红

image-20221010093734175

然后鼠标停留在报红上,选择左下角,添加对应的表自动修复

  • dao层

Dao.java,继承JpaRepository<>,要添加泛型

package com.xsh.sbjpa.dao;

import com.xsh.sbjpa.entity.GoodsInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

//JpaRepository<GoodsInfo,Integer> ,第一个参数是实体类的类型,第二个参数是实体类的主键的类型
@Repository//(翻译:仓库)持久层的注解
public interface GoodsInfoDao extends JpaRepository<GoodsInfo,Integer> {
}
  • service层

定义接口IService.java

package com.xsh.sbjpa.service;

import com.xsh.sbjpa.entity.GoodsInfo;

import java.util.List;

public interface IGoodsInfoService {
    //查找一个
    GoodsInfo getOne(Integer giId);

    //查找所有
    List<GoodsInfo> getAll();

    //增加
    boolean addGoodsInfo(GoodsInfo goodsInfo);

    //修改
    boolean updateGoodsInfo(GoodsInfo goodsInfo);

    //删除
    boolean deleteGoodsInfo(Integer giId);
}

注意:@Service注解是添加在实现类上,而不是接口类上

ServiceImpl实现接口IService.java

package com.xsh.sbjpa.service.impl;

import com.xsh.sbjpa.dao.GoodsInfoDao;
import com.xsh.sbjpa.entity.GoodsInfo;
import com.xsh.sbjpa.service.IGoodsInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service//service层的注解
public class GoodsInfoServiceImpl implements IGoodsInfoService {

    @Autowired
    GoodsInfoDao dao;//自动装配dao

    @Override
    public GoodsInfo getOne(Integer giId) {
        //选择方法时,看参数和返回值
//        dao.getReferenceById(1002)//报错暂时不用
        //findById方法:如果传入的id找不到对应的数据,get时就会抛异常
        Optional<GoodsInfo> opt = dao.findById(giId);
        if(opt.isPresent()){//用opt。isPresent()进行判断,如果为true,表示查询到了数据,可以get
            return opt.get();
        }
        return null;//否则就表示没有数据,返回空
    }

    @Override
    public List<GoodsInfo> getAll() {
        return dao.findAll();
    }

    @Override
    public boolean addGoodsInfo(GoodsInfo goodsInfo) {
        GoodsInfo gi = new GoodsInfo();
        gi.setGiName(goodsInfo.getGiName());
        boolean exists = dao.exists(Example.of(gi));//只根据名字进行查询,Example.of()的参数是实体类
        if(!exists){//如果同名不加,不同名添加
            dao.save(goodsInfo);//添加
            return true;
        }
        return false;
    }

    @Override
    public boolean updateGoodsInfo(GoodsInfo goodsInfo) {
        dao.save(goodsInfo);//save方法有两个功能,有id时修改,没有id时增加
        return true;//敷衍
    }

    @Override
    public boolean deleteGoodsInfo(Integer giId) {
        dao.deleteById(giId);
        return true;//敷衍
    }
}
  • 测试
package com.xsh.sbjpa;

import com.xsh.sbjpa.entity.GoodsInfo;
import com.xsh.sbjpa.service.IGoodsInfoService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class SbjpaApplicationTests {

    @Autowired
    IGoodsInfoService service;

    //测试查询
    @Test
    void testSelect() {
        //测试单个查询
        GoodsInfo one = service.getOne(1002);
        System.out.println(one);

        //测试全部查询
        List<GoodsInfo> all = service.getAll();
        System.out.println(all);
    }

    //测试插入
    @Test
    void testInsert(){
        GoodsInfo goodsInfo = new GoodsInfo();
        goodsInfo.setGiName("大西瓜");
        goodsInfo.setGiId(1020);
        boolean b=service.addGoodsInfo(goodsInfo);
        System.out.println("插入"+b);//存在同名插入失败

        goodsInfo.setGiName("大西瓜333");
        boolean b1=service.addGoodsInfo(goodsInfo);
        System.out.println("插入"+b1);//不存在同名插入成功
    }

    //测试修改
    @Test
    void testUpdate() {
        GoodsInfo goodsInfo = new GoodsInfo();
        goodsInfo.setGiName("大西瓜");
        goodsInfo.setGiId(1020);
        goodsInfo.setGiNum(233);
        boolean b=service.updateGoodsInfo(goodsInfo);
        System.out.println("更新"+b);
    }

    //测试删除
    @Test
    void testDelete() {
        boolean b=service.deleteGoodsInfo(1020);
        System.out.println("删除"+b);
    }
}

6.3设置事务

事务(Transaction)是一个不可分割的执行单位,事务中包括的操作要么都做,要么都不做。

使用@Transactional注解可以将方法中执行的sql语句都设置为同一事务

@Transactional使用在方法前,表示为该方法设置事务

@Transactional使用在类前,表示为该类的所有方法设置事务

例:

  • IService.java接口中添加方法
//测试事务
    boolean testTransactional1();
    boolean testTransactional2();
  • ServiceImpl中实现方法如下

testTransactional1没有添加注解,testTransactional2添加了注解

 @Override
    public boolean testTransactional1() {
        GoodsInfo one = new GoodsInfo();
        one.setGiId(1021);
        one.setGiName("执行1");
        dao.save(one);//插入第一条数据,不会出错

        GoodsInfo two = new GoodsInfo();
        one.setGiId(1021);
        dao.save(two);//插入第二条数据,数据库中name有非空约束,因此插入two会出错

        return true;
    }

    @Override
    @Transactional//设置事务:业务方法中的数据库操作要么都成功,要么都失败,此注解可以放在类前,表示此类中的方法都设置事务
    public boolean testTransactional2() {
        GoodsInfo one = new GoodsInfo();
        one.setGiId(1021);
        one.setGiName("执行1");
        dao.save(one);//插入第一条数据,不会出错

        GoodsInfo two = new GoodsInfo();
        one.setGiId(1021);
        dao.save(two);//插入第二条数据,数据库中name有非空约束,因此插入two会出错

        return true;
    }
  • 测试

    //测试事务
    @Test
    void testTransactional1() {
        service.testTransactional1();//没有设置事务,即使第二个插入错误,第一个插入仍然成功
    }
    @Test
    void testTransactional2() {
        service.deleteGoodsInfo(1021);
        service.testTransactional2();//设置了事务,第二个插入错误,第一个插入失败
    }
    

数据库中的结果:

testTransactional1()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bRxNPV7h-1665835053089)(img/image-20221010115323831.png)]

testTransactional2()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0b824nKX-1665835053090)(img/image-20221010115442125.png)]

补充:事务的概念回顾

事务是恢复和并发控制的基本单位;

在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或者整个程序

特性:

事务具有四个特性(ACID):

? 原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)。

  • 原子性(atomicity),一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做
  • 一致性(consistency),事务必须是使数据库从一个一致性状态变到另一个一致性状态,一致性与原子性是密切相关的
  • 隔离性(isolation),一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰
  • 持久性(durability),持久性也成为永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响

6.4复杂查询

@Autowired
GoodsInfoDao dao;

分页、排序、分页并排序(直接测试dao)

package com.xsh.sbjpa;

import com.xsh.sbjpa.dao.GoodsInfoDao;
import com.xsh.sbjpa.entity.GoodsInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;

import java.util.List;

//jpa的复杂查询
@SpringBootTest
public class TestGoodsInfoDao {
    @Autowired
    GoodsInfoDao dao;

    //分页的使用
    @Test
    public void test1(){
        int page = 1;//注意page是从0开始的,0页表示第一页数据
        int size=3;
        PageRequest pageRequest = PageRequest.of(page, size);
        Page<GoodsInfo> all = dao.findAll(pageRequest);
        System.out.println(all.getContent());
    }

    //排序
    @Test
    public void test2(){
        //"giNum","giPrice"是属性名,不是字段名
        //1.多个字段排序,统一的升序或者降序
        List<GoodsInfo> all = dao.findAll(Sort.by(Sort.Direction.ASC, "giNum", "giPrice"));
        //2多个字段排序,排序方式不一致
        dao.findAll(Sort.by(Sort.Order.asc("giNum"),Sort.Order.desc("giPrice")));
    }

    //分页和排序一起使用
    @Test
    public void test3(){
        //排序的设置,放在PageRequest对象中
        PageRequest pageRequest = PageRequest.of(0, 5, Sort.by(Sort.Order.desc("giNum"), Sort.Order.desc("giPrice")));
        dao.findAll(pageRequest);
    }
}

使用Example查询

使用等于条件

//使用Example:拼接等于和and的查询
@Test
public void test4(){
    GoodsInfo goodsInfo = new GoodsInfo();
    goodsInfo.setGiName("大西瓜");
    List<GoodsInfo> all = dao.findAll(Example.of(goodsInfo));
    System.out.println(all);
}

使用方法命名规则

如果需要使用等于以外的查询条件,需要在Dao.java中自定义方法,方法按照下表命名即可自动添加对应的查询条件

image-20221010154430493

例:

package com.xsh.sbjpa.dao;

import com.xsh.sbjpa.entity.GoodsInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

//JpaRepository<GoodsInfo,Integer> ,第一个参数是实体类的类型,第二个参数是实体类的主键的类型
@Repository//(翻译:仓库)持久层的注解
public interface GoodsInfoDao extends JpaRepository<GoodsInfo,Integer> {
    //按方法命名规则,自定义查询的方法
    //查询价格大于多少
    List<GoodsInfo> findByGiPriceGreaterThan(Double giPrice);

    //查询价格大于,或者数量小于等于
    List<GoodsInfo> findByGiPriceGreaterThanOrGiNumLessThanEqual(Double giPrice,Integer giNum);
}
@Test
public void test5(){
    List<GoodsInfo> all = dao.findByGiPriceGreaterThan(10.0);
    List<GoodsInfo> all1 = dao.findByGiPriceGreaterThanOrGiNumLessThanEqual(10.0,20);
}

自定义方法查询

  • hql

Dao.java

//自定义方法
//hql:从对象中查询,框架转换为SQL
//sql:从table中查询
@Query("from GoodsInfo where giName like :giName and giPrice > :giPrice")//hql
List<GoodsInfo> selectByWhere(String giName,Double giPrice);

测试

//自定义的方法。自己写hql/sql
@Test
public void test6(){
    dao.selectByWhere("%西%",10.0);
}
  • sql

Dao.java

//--nativeQuery,设置为使用sql,默认为false,表示使用hql
@Query(value = "select gt_name as 'name',sum(gi_num) as num from goods_info,goods_type where goods_info.gt_id=goods_type.gt_id group by goods_type.gt_id",nativeQuery = true)
List<Map<String,Object>> selectByGroupGtId();

测试

@Test
public void test7(){
    List<Map<String, Object>> list = dao.selectByGroupGtId();
    for (Map<String, Object> map : list) {
        Object name = map.get("name");
        Object num = map.get("num");
        System.out.println(name+"  "+num);
    }
}

结果(注意Map的使用)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u0BfXS5g-1665835053091)(img/image-20221010163940977.png)]

6.5多表查询

注意:不要使用Lombok中的@ToString方法,会造成StackOverflowError,自己添加toString方法,不要转化字段对应外的属性

6.5.1一对多

一:JavaClass.java (table:java_class)

多:Student.java (table:student)

单向一对多

一:

package com.xsh.sbstujpa.entity;

import lombok.Data;

import javax.persistence.*;
import java.util.List;

@Entity
@Data
@Table(name="java_class")
public class JavaClass {
    @Id
    @Column(name = "c_id")
    private Integer cId;
    @Column(name = "c_name")
    private String cName;
    @Column(name = "c_intro")
    private String cIntro;

    //管理关系相关的属性
    @OneToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name="c_id")//外键关联的列
    private List<Student> stus;
}

多:

package com.xsh.sbstujpa.entity;

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Data
@Table(name="student")
public class Student {
    @Id
    @Column(name = "stu_id")
    private Integer stuId;
    @Column(name = "stu_name")
    private String stuName;
    @Column(name = "stu_sex")
    private String stuSex;
    @Column(name = "c_id")
    private Integer cId;
}

单向多对一

一:

package com.xsh.sbstujpa.entity;

import lombok.Data;

import javax.persistence.*;
import java.util.List;

@Entity
@Data
@Table(name="java_class")
public class JavaClass {
    @Id
    @Column(name = "c_id")
    private Integer cId;
    @Column(name = "c_name")
    private String cName;
    @Column(name = "c_intro")
    private String cIntro;

//    //管理关系相关的属性
//    @OneToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL)
//    @JoinColumn(name="c_id")//外键关联的列
//    private List<Student> stus;
}

多:

package com.xsh.sbstujpa.entity;

import lombok.Data;

import javax.persistence.*;

@Entity
@Data
@Table(name="student")
public class Student {
    @Id
    @Column(name = "stu_id")
    private Integer stuId;
    @Column(name = "stu_name")
    private String stuName;
    @Column(name = "stu_sex")
    private String stuSex;
    @Column(name = "c_id",insertable = false,updatable = false)
    private Integer cId;

    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="c_id")
    private JavaClass javaClass;
}

双向一对多&多对一

一:

package com.xsh.sbstujpa.entity;

import lombok.Data;

import javax.persistence.*;
import java.util.List;

@Entity
@Data
@Table(name="java_class")
public class JavaClass {
    @Id
    @Column(name = "c_id")
    private Integer cId;
    @Column(name = "c_name")
    private String cName;
    @Column(name = "c_intro")
    private String cIntro;

    //管理关系相关的属性
    //mappedBy="javaClass:由多方维护关系,
    //"javaClass"是多方中有关联关系的属性名
    @OneToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL,
    mappedBy = "javaClass")
//    @JoinColumn(name="c_id")//设置了多方维护关系,那么就不需要@JoinColumn
    private List<Student> stus;
}

多:

package com.xsh.sbstujpa.entity;

import lombok.Data;

import javax.persistence.*;

@Entity
@Data
@Table(name="student")
public class Student {
    @Id
    @Column(name = "stu_id")
    private Integer stuId;
    @Column(name = "stu_name")
    private String stuName;
    @Column(name = "stu_sex")
    private String stuSex;
    @Column(name = "c_id",insertable = false,updatable = false)
    private Integer cId;

    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="c_id")
    private JavaClass javaClass;
}

6.5.2多对多

course表对应student表,数据库中需要多对多联系的中间表

单向多对多

package com.xsh.sbstujpa.entity;

import lombok.Data;

import javax.persistence.*;
import java.util.List;

@Entity
@Data
@Table(name = "course")
public class Course {
    @Id
    @Column(name = "c_id")
    private String cId;
    @Column(name = "c_name")
    private String cName;
    @Column(name = "t_id")
    private Integer tId;

    //课程找到学生
    @ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    @JoinTable(name="cou_stu",
            joinColumns = {@JoinColumn(name="c_id")},//中间表相关的列名(与此表对应的外键)
            inverseJoinColumns = {@JoinColumn(name = "stu_id")}//中间表相关的列名(另一个表的外键)
    )
    private List<Student> stus;
}

双向多对多

在一对多的基础上另一个表:

package com.xsh.sbstujpa.entity;

import lombok.Data;
import lombok.ToString;

import javax.persistence.*;
import java.util.List;

@Entity
@Data
//@ToString
@Table(name="student")
public class Student {
    @Id
    @Column(name = "stu_id")
    private Integer stuId;
    @Column(name = "stu_name")
    private String stuName;
    @Column(name = "stu_sex")
    private String stuSex;
    @Column(name = "c_id",insertable = false,updatable = false)
    private Integer cId;

    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="c_id")
    private JavaClass javaClass;

    //委托另外一方维护设置
    @ManyToMany(fetch = FetchType.EAGER,
        mappedBy = "stus")
    private List<Course> courses;

    @Override
    public String toString() {
        return "Student{" +
                "stuId=" + stuId +
                ", stuName='" + stuName + '\'' +
                ", stuSex='" + stuSex + '\'' +
                ", cId=" + cId +
                '}';
    }
}

#### 6.5.3一对一

只需要在一方使用添加对应属性和@OneToOne注解和@JoinColumn注解

thymeleaf官网https://www.thymeleaf.org/

如果需要在springboot中使用thymeleaf和SSM中使用jsp的方式类似

将html文件放到resources/templates下

在html中设置一个thymeleaf官网的命名空间,一般用th作为标识符

```html
<!-- 设置官网的命名空间-->
<html lang="en" xmlns:th="https://www.thymeleaf.org/">

在需要显示动态数据的标签上添加th:属性=${响应的变量名},text标识标签中的文本内容

    <!-- ${word},从请求中传过来-->
    <h2 th:text="${word}">欢迎xx!</h2>
    <img th:src="@{/img/c5.jpg}">

或者使用thymeleaf的其他选项,如循环、判断等

<table>
    <tr>
        <td>班级名</td>
        <td>班级简介</td>
    </tr>
    <tr th:each="jl:${javaclass}">
        <td th:text="${jl.cName}">名字</td>
        <td th:text="${jl.cIntro}">介绍</td>
    </tr>
</table>

例:

<!DOCTYPE html>
<!-- 设置官网的命名空间-->
<html lang="en" xmlns:th="https://www.thymeleaf.org/">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/css/main.css">
    <script src="/js/jquery.js"></script>
    <title>Title</title>
</head>
<body>
    <!-- ${word},从请求中传过来-->
    <h2 th:text="${word}">欢迎xx!</h2>
    <table>
        <tr>
            <td>班级名</td>
            <td>班级简介</td>
        </tr>
        <tr th:each="jl:${javaclass}">
            <td th:text="${jl.cName}">名字</td>
            <td th:text="${jl.cIntro}">介绍</td>
        </tr>
    </table>
    <img th:src="@{/img/c5.jpg}">
    <script>
        $("tr").css("color","white")
    </script>
</body>
</html>

在controller的请求中和使用jsp时一样,添加ModelMap参数来响应数据,方法返回html去掉后缀的文件名

@Controller
public class TClassController {

    //创建logger对象,在需要记录日志的地方,调用logger对象的方法,记录日志
    Logger logger = LoggerFactory.getLogger(TClassController.class);

    @Autowired
    JavaClassDao dao;

    @RequestMapping("list")
    public String query(ModelMap map){
        map.put("word","tom,下午好");
        List<JavaClass> all = dao.findAll();
        map.put("javaclass",all);
        return "first";//找html页面
    }
}

private Integer stuId;
@Column(name = “stu_name”)
private String stuName;
@Column(name = “stu_sex”)
private String stuSex;
@Column(name = “c_id”,insertable = false,updatable = false)
private Integer cId;

@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="c_id")
private JavaClass javaClass;

//委托另外一方维护设置
@ManyToMany(fetch = FetchType.EAGER,
    mappedBy = "stus")
private List<Course> courses;

@Override
public String toString() {
    return "Student{" +
            "stuId=" + stuId +
            ", stuName='" + stuName + '\'' +
            ", stuSex='" + stuSex + '\'' +
            ", cId=" + cId +
            '}';
}

}

6.5.3一对一

只需要在一方使用添加对应属性和@OneToOne注解和@JoinColumn注解

thymeleaf官网https://www.thymeleaf.org/

如果需要在springboot中使用thymeleaf和SSM中使用jsp的方式类似

将html文件放到resources/templates下

在html中设置一个thymeleaf官网的命名空间,一般用th作为标识符

<!-- 设置官网的命名空间-->
<html lang="en" xmlns:th="https://www.thymeleaf.org/">


在需要显示动态数据的标签上添加th:属性=${响应的变量名},text标识标签中的文本内容

```html
    <!-- ${word},从请求中传过来-->
    <h2 th:text="${word}">欢迎xx!</h2>
    <img th:src="@{/img/c5.jpg}">

或者使用thymeleaf的其他选项,如循环、判断等

<table>
    <tr>
        <td>班级名</td>
        <td>班级简介</td>
    </tr>
    <tr th:each="jl:${javaclass}">
        <td th:text="${jl.cName}">名字</td>
        <td th:text="${jl.cIntro}">介绍</td>
    </tr>
</table>

例:

<!DOCTYPE html>
<!-- 设置官网的命名空间-->
<html lang="en" xmlns:th="https://www.thymeleaf.org/">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/css/main.css">
    <script src="/js/jquery.js"></script>
    <title>Title</title>
</head>
<body>
    <!-- ${word},从请求中传过来-->
    <h2 th:text="${word}">欢迎xx!</h2>
    <table>
        <tr>
            <td>班级名</td>
            <td>班级简介</td>
        </tr>
        <tr th:each="jl:${javaclass}">
            <td th:text="${jl.cName}">名字</td>
            <td th:text="${jl.cIntro}">介绍</td>
        </tr>
    </table>
    <img th:src="@{/img/c5.jpg}">
    <script>
        $("tr").css("color","white")
    </script>
</body>
</html>

在controller的请求中和使用jsp时一样,添加ModelMap参数来响应数据,方法返回html去掉后缀的文件名

@Controller
public class TClassController {

    //创建logger对象,在需要记录日志的地方,调用logger对象的方法,记录日志
    Logger logger = LoggerFactory.getLogger(TClassController.class);

    @Autowired
    JavaClassDao dao;

    @RequestMapping("list")
    public String query(ModelMap map){
        map.put("word","tom,下午好");
        List<JavaClass> all = dao.findAll();
        map.put("javaclass",all);
        return "first";//找html页面
    }
}

end

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:18:51  更:2022-10-17 12:21:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/30 14:00:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码