Mybatis

动态SQL

普通式

<insert id="insertRole" parameterType="com.edu.ssm.po.Role">
    <!--<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
        select LAST_INSERT_ID() 
    </selectKey>-->
      insert into Role(username,birthday,sex,address) 
      values(#{username},#{birthday},#{sex},#{address})
    </insert>

使用动态sql trim标签,集齐了where set的强大标签

<insert id="insertRole" parameterType="com.edu.ssm.po.Role">
      insert into Role
     <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null and id!='' ">
        id,
      </if>
      <if test="username != null">
        username,
      </if>
      <if test="birthday != null">
        birthday,
      </if>
      <if test="sex != null">
        sex,
      </if>
      <if test="address != null">
        address,
      </if>
    </trim>
      <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="username != null">
        #{username,jdbcType=VARCHAR},
      </if>
      <if test="birthday != null">
        #{birthday,jdbcType=DATE},
      </if>
      <if test="sex != null">
        #{sex,jdbcType=CHAR},
      </if>
      <if test="address != null">
        #{address,jdbcType=VARCHAR},
      </if>
    </trim>
    </insert>

使用注解的方式注入对象

List<Role> findRoleByOj(@Param("role") Role role);
<select id="findRoleByOj" parameterType="com.edu.ssm.po.Role" resultType="com.edu.ssm.po.Role">
        select * from role 
        <where>
        <if test="role.id!=null and role.id!='' "> <!--这个要注意-->
         and id = #{role.id}
         </if>
        </where>     
    </select>

没有注解的方式

List<Role> findRoleByOj(Role role);
<select id="findRoleByOj" parameterType="com.edu.ssm.po.Role" resultType="com.edu.ssm.po.Role">
        select * from role 
        <where>
        <if test="id!=null and id!='' "> <!--这个要注意-->
         and id = #{id}
         </if>
        </where>     
    </select>

模板

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">
 <mapper namespace="com.edu.ssm.mapper.RoleMapper"> 

</mapper>

src/SqlMapConfig.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>
    <!-- 和spring整合后 environments配置将废除-->
    <environments default="development">
        <environment id="development">
        <!-- 使用jdbc事务管理-->
            <transactionManager type="JDBC" />
        <!-- 数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/springmvc?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/edu/ssm/mapper/ItemsMapper.xml"/>
        <mapper resource="com/edu/ssm/mapper/RoleMapper.xml"/>
    </mappers>
</configuration>

当 SQL 语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。 举个例子,如果你想通过任何一列从表中 select 数据时,不需要像下面这样写:

@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);

@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);

@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);

// and more "findByXxx" method可以只写这样一个方法: 
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);其中 ${column} 会被直接替换,而 #{value} 会被使用 ? 预处理。 因此你就可以像下面这样来达到上述功能: 
User userOfId1 = userMapper.findByColumn("id", 1L);
User userOfNameKid = userMapper.findByColumn("name", "kid");
User userOfEmail = userMapper.findByColumn("email", "noone@nowhere.com");

动态sql

choose
when
when
otherwise
与if不同的是
choose只能是单选
执行完一个就不在找了
if还在继续执行

where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。

如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

使用if 如果有的值吗没有传就多出来一个and

所以使用<where>来取消前面多于的and</where>

<select id="findActiveBlogLike" resultType="Blog">
      SELECT * FROM BLOG
  <where>
    <if test="state != null and state !='' ">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

ResultMap 通常在联合查询使用

  <resultMap id="BaseResultMap" type="com.example.mybatis.entity.Items">
    <result column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="price" jdbcType="REAL" property="price" />
    <result column="pic" jdbcType="VARCHAR" property="pic" />
    <result column="createtime" jdbcType="TIMESTAMP" property="createtime" />
  </resultMap>

INSERT INTO table_name ( field1, field2,...fieldN )
                       VALUES
                       ( value1, value2,...valueN );
   <insert id="insert">
        insert  into school
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="province != null">
                province,
            </if>
            <if test="code != null">
                code,
            </if>
            <if test="major != null">
                major,
            </if>
            <if test="schoolcode != null">
                schoolcode,
            </if>
            <if test="schoolname != null">
                schoolname,
            </if>
            <if test="year != null">
                year,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="province != null">
                #{province},
            </if>
            <if test="code != null">
                #{code},
            </if>
            <if test="major != null">
                #{major},
            </if>
            <if test="schoolcode != null">
                #{schoolcode},
            </if>
            <if test="schoolname != null">
                #{schoolname},
            </if>
            <if test="year != null">
               #{year},
            </if>
        </trim>
    </insert>

DROP TABLE table_name ; 删除整个表,包括表结构
删除表内数据,用 delete。格式为:
delete from 表名 where 删除条件;

实例:删除学生表内姓名为张三的记录。
delete from  student where  T_name = "张三";

清除表内数据,保存表结构,用 truncate。格式为:
truncate table 表名;

实例:清除学生表内的所有数据。
truncate  table  student;

UPDATE table_name SET field1=new-value1, field2=new-value2
[WHERE Clause]
 <update id="update">
        update school
        <set>
            <if test="province != null">
                province=#{province},
            </if>
            <if test="code != null">
                code=#{code},
            </if>
            <if test="major != null">
                major=#{major},
            </if>
            <if test="schoolcode != null">
                schoolcode=#{schoolcode},
            </if>
            <if test="schoolname != null">
               schoolname= #{schoolname},
            </if>
            <if test="year != null">
                year=#{year},
            </if>
    </set>
        where  id=#{id}
    </update>

模糊查询

        <select id="selectprovince" resultType="com.edu.entity.School">
            select * from school where province like concat('%',#{province},'%');
        </select>
SELECT column_name,column_name
FROM table_name
[WHERE Clause]
[LIMIT N][ OFFSET M]
select _column,_column from _table [where Clause] [limit N][offset M]
 select * : 返回所有记录
 limit N : 返回 N 条记录
 offset M : 跳过 M 条记录, 默认 M=0, 单独使用似乎不起作用
 limit N,M : 相当于 limit M offset N , 从第 N 条记录开始, 返回 M 条记录
实现分页:

select * from _table limit (page_number-1)*lines_perpage, lines_perpage

或

select * from _table limit lines_perpage offset (page_number-1)*lines_perpage
/*websites  表名   NAME alexa url country  字段*/
SELECT * FROM websites;                      /* 查询表所有数据 */

SELECT NAME FROM websites;                   /* 查询表字段数据 */

SELECT * FROM websites where name = "广西";   /* 查询表字段下条件数据 */

SELECT * from websites where name like "_o%"; /* 模糊查询表下数据 */

SELECT * FROM websites where id BETWEEN "1" AND "5";    /* 查询表下字段范围数据 */

SELECT * FROM websites WHERE name in ("广西","百度");    /* 查询表字段下固定条件数据 */

SELECT DISTINCT country FROM Websites;                  /* 查询去重值 */

SELECT * FROM Websites WHERE country = "CN" AND alexa > 50;  /*查询表下范围条件数据*/

SELECT * FROM Websites WHERE country = "USA" OR country="sh"; /* 查询表下条件不同值 */

SELECT * FROM Websites ORDER BY alexa;                      /* 查询表下值排序结果 */

SELECT * FROM Websites ORDER BY alexa DESC;                 /* 查询表下排序结果降序 */

SELECT * FROM Websites LIMIT 2;      /* 查询表下范围数据 */

SELECT name as zzz from websites;    /*别名查询表下数据*/

多表关联查询

select 字段 from 表1 left join 表2 on  条件 (一般为表1与表2的关联条件)

请求数据的几种方式已经springmvc的接受

一. form表单提交

GET方式

前端表单传参

  <form action="http://localhost:8080/test" method="get">
    <input type="text" name="username" />
    <input type="text" name="password"/>
    <input type="submit" value="Submit" />
  </form>

后端参数接收,因为 form 表单使用 get 方法的时候,Content type 的值默认为空。所以后台接收代码不需要指定 consumes 属性

    @ResponseBody
    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public String test1(@RequestParam(value="username") String username,
                        @RequestParam(value="password") String password){
        System.out.println("======GET======");
        System.out.println("username=" + username);
        System.out.println("password=" + password);
        return "SUCCESS";
    }

打印结果:

======GET======
username=wangbo
password=123456

可以看出 FORM 表单发出的 GET 请求直接通过注解 @RequestParam 进行参数接口即可。

POST方式

前端表单传参

  <form action="http://localhost:8080/test" method="post">
    <input type="text" name="username" />
    <input type="text" name="password"/>
    <input type="submit" value="Submit" />
  </form>

后端参数接收,

因为 form 表单使用 post 方法的时候,

Content type 的值默认为 application/x-www-form-urlencoded;charset=UTF-8。

所以后台接收代码需要指定 consumes 属性。

consumes = "application/x-www-form-urlencoded;charset=UTF-8"
    @ResponseBody
    @RequestMapping(value = "/test", method = RequestMethod.POST, consumes = "application/x-www-form-urlencoded;charset=UTF-8")
    public String test(@RequestParam(value="username") String username,
                       @RequestParam(value="password") String password,
                       User user){
        System.out.println("======POST======");
        System.out.println("username=" + username);
        System.out.println("password=" + password);
        System.out.println("user=" + user);
        return "SUCCESS";
    }

打印结果

======POST======
username=wangbo
password=123456
user=username=wangbo; password=123456

可以看出,FORM 表单发出的 POST 请求可以直接通过注解 @RequestParam 进行参数接收,

也可以使用字段对应封装的 Java Bean 对象来接收参数。注意 Java Bean 对象上不需要注解。

User 代码,为了更清楚的打印对象,重写了 toString 代码。

二. resuful风格的获取get的提交

@PathVariable

只能接收 URL 路径里的参数。

function update(e) {
    window.location.href="/selectItem/"+e;
}
   @GetMapping(value ="/selectItem/{id}")
    public String  selectItem(@PathVariable("id") Integer id,Model model){
        School school= schoolService.selectItem(id);
        model.addAttribute("school",school);
        return "updatelist";
    }

@RequestParam

只能接收 URL 问号后跟着的参数,不管是 GET 还是 POST,虽然一般只有 GET 请求才会在 URL 后边跟参数,问号 ? 后面的部分,使用 & 区分参数。

http://localhost:8080/api/user/login/test?username=2222222&pass=333333333
@RequestParam("username")String username,
@RequestParam("pass")String pass

三. Post请求

@RequestBody

只能接收请求体中的参数,也就是只能是 POST 请求才有请求体,GET 请求没有请求体,请求体分两种情况参数

(1)使用String接收

比如前端参数在请求体中传的是 username=18514335982&pass=12345,Content type 为 text/plain;charset=UTF-8

则后台接收到的 param 即为 username=18514335982&pass=12345 格式

@RequestBody String param

(2)使用封装的 bean 或者 JSONObject 接收(常用)

前端必须使用 JSON 格式的数据,Content-Type 必须为 application/json,请求体中参数为 {"username":"18514335982","pass":"12345"}

@RequestBody User user
@RequestBody JSONObject jsonObject
@PostMapping("/login/test")
    public ResultBuilder userLogin1(@RequestHeader(Constants.ACCEPT_VERSION)String version,
                                    @RequestHeader(Constants.ACCESS_TOKEN)String token,
                                    @RequestParam("username")String username,
                                    @RequestParam("pass")String pass,
                                    @RequestBody User user){

        logger.debug("username======" + username);
        logger.debug("pass======" + pass);
        logger.debug("user---username==" + user.getUsername());
        logger.debug("user---pass==" + user.getPass());
        return new ResultBuilder(StatusCode.SUCCESS);
    }

四.ajax发送请求

var data = {'id':id,'name':name};
$.ajax({ 
            type:"POST", 
            url:"user/saveUser", 
            dataType:"json",      
            //contentType:"application/json", //不能添加这个头           
            data:data, //这里不能进行JSON.stringify,发送请求的数据在:form data
            success:function(data){ 

            } 
         });
//看成单值
@RequestMapping(value = "save", method = {RequestMethod.POST }) 
     @ResponseBody  
     public void save(@RequestParam int id,String name) { //这里字段要跟前端一致,@RequsetParam 可以不加,默认调用的就是它

     }
//看成对象
@RequestMapping(value = "save", method = {RequestMethod.POST }}) 
     @ResponseBody  
     public void save(User user) { //前端字段跟对象属性一致
                                   //自动转化成改对象
     }

json对象转成字符串后传值

function addcart(productid,number,price){
    var cart={
                "userid":1,
                "productid":123,
                "number":213,
                "price":3
            }
    $.ajax({
        type : "POST",
        url : "${pageContext.request.contextPath}/useraddCart",
         dataType:"json",   
         contentType:"application/json",
         data:JSON.stringify(cart),
        success : function(data){
         console.log(data)
        }
        })
}
    @RequestMapping(value="/useraddCart",method=RequestMethod.POST)
    @ResponseBody
    public HappyFarmCart useraddCart(@RequestBody HappyFarmCart happyFarmCart){

        System.out.println(happyFarmCart.toString());
    return happyFarmCart;
    }

将对象JSON.stringify后,以第一种方式传递,可实现对象中存对象 {'userList':users,'key1':value1}

var user = {'id':id,'name':name};
var jsonStrGoods = JSON.stringify({'gid':gid,...});
$.ajax({ 
              type:"POST", 
              url:"user/saveUser", 
              dataType:"json",      
             // contentType:"application/json", //不添加这个头           
              data:{'user':JSON.stringify(user),'goods':jsonStrGoods }, //发送请求的数据在request payload
              success:function(data){ 

             } 
          });
//看成单值
@RequestMapping(value = "save", method = {RequestMethod.POST }}) 
     @ResponseBody  
     public void save(@RequestParam String user,String goods) { //这里字段要跟前端一致,@RequsetParam 可以不加,默认调用的就是它
          User u= JSON.parseObject(user, User .class);//alibaba.fastjson转换成对象
     }
//看成对象
@RequestMapping(value = "save", method = {RequestMethod.POST }}) 
     @ResponseBody  
     public void save(UserAndGoods ug) { //没试过,猜测应该是这样,前端字段跟对象属性一致
                                   //自动转化成改对象
     }

传数组

var arr = str.split(',');
    $.ajax({
        url:'/appollo-console/manage/user/names/validation',
        data:{
            names:arr
        },
        traditional: true,//必须
        type:'post',
        dataType:'json',
        success:function(res){
            alert(res);
        }
    })
@PostMapping("/names/validation")
    @ResponseBody
    public List<String> validateUserName(String[] names){
        List<String> notValidNames = Lists.newArrayList();
        notValidNames = userService.findNotValidNames(Arrays.asList(names));
        return notValidNames;
    }

总结:

1.如果用JSON.stringify()将对象转成字符串,就需要在ajax请求中指定contentType 为 application/json,且后台需添加 @RequestBody注解;

2.如果直接传json对象则跟上面的相反,不能指定contentType为 application/json,其默认类型是 application/x-www-form-urlencoded

五.axios请求方式

get请求

    testGet: function () {
      axios({
        method: 'get',
        url: '/test/greeting',
        params: {
          firstName: 'Fred',
          lastName: 'Flintstone'
        }
      }).then(function (response) {
        console.log(response);
      }).catch(function (error) {
        console.log(error);
      });
    },

post请求

testPost: function () {
                var params = new URLSearchParams();
                params.append('name', 'hello jdmc你好');
                params.append('id', '2');
                axios({
                  method: 'post',
                  url: '/test/greeting2',
                  data:params
        //          data: {id: '3', name: 'abc'}
                }).then(function (response) {
                  console.log(response);
                }).catch(function (error) {
                  console.log(error);
                })
              }

注意:

在使用post方式的时候传递参数有两种方式,一种是普通方式,一种是json方式,如果后台接受的是普通方式,那么使用上述方式即可。

普通的formed方式

    var params = new URLSearchParams();
    params.append('name', 'hello jdmc你好');
    params.append('id', '2');
    data:params

后台接收参数:

    public Student greeting2(int id,String name) 

json方式

    data: {id: '3', name: 'abc'}

后台接收参数

    public Object greeting2(@RequestBody Object data) 

在jsp页面请求之后渲染到html

web请求静态资源上下文

${pageContext.request.contextPath}

yml基本模板

server: 
    port: 8080

spring:  
     datasource:   
        username: root    
        password: 123456   
        url: jdbc:mysql://localhost:3306/springmvc?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC    
        driver-class-name: com.mysql.cj.jdbc.Drivermybatis:
    #一定不能错,要不然Mapper扫描不到,在主类配置MapperScan  

mapper-locations: classpath:mapper/*.xml  
    type-aliases-package: com.edu.entity

resources:    
    static-locations: ["/templates/","/static/",]

thymeleaf:
    prefix: classpath:/templates/    
    suffix: .html    
    cache: false

Mysql

SQL HAVING 子句

HAVING 子句

在 SQL 中增加 HAVING 子句原因是,WHERE 关键字无法与聚合函数一起使用。

HAVING 子句可以让我们筛选分组后的各组数据。

SQL HAVING 语法

SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value;

springmvc

<?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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- @Controller注解扫描,里面的类标上注解可以识别 ,识别controller下的类-->
    <context:component-scan base-package="cn.itheima.controller"></context:component-scan>

    <!-- 注解驱动:
             根据 扫面  @RequestMapping等注解
            替我们显示的配置了最新版的注解的处理器映射器和处理器适配器 -->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!-- 配置视图解析器 
    作用:在controller中指定页面路径的时候就不用写页面的完整路径名称了,可以直接写页面去掉扩展名的名称
    -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 真正的页面路径 =  前缀 + 去掉后缀名的页面名称 + 后缀 -->
        <!-- 前缀 -->
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <!-- 后缀 -->
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!-- 配置自定义转换器 
    注意: 一定要将自定义的转换器配置到注解驱动上
    -->
        <!-- 指定自定义转换器的全路径名称 -->
    <!--  <bean id="conversionService"
        class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>

                <bean class="cn.itheima.controller.converter.CustomGlobalStrToDateConverter"/>
            </set>
        </property>
    </bean>-->
    <!-- 与静态文件的加载有关
    <mvc:resources location="/,classpath:/META-INF/publicResources/" mapping="/resources/**"/>
    以上配置将Web根路径"/"及类路径下 /META-INF/publicResources/ 的目录映射为/resources路径。假设Web根路径下拥有images、js这两个资源目录,在images下面有bg.gif图片,在js下面有test.js文件,
    则可以通过 /resources/images/bg.gif 和 /resources/js/test.js 访问这二个静态资源。
    假设WebRoot还拥有images/bg1.gif 及 js/test1.js,
    则也可以在网页中通过 /resources/images/bg1.gif 及 /resources/js/test1.js 进行引用。

     -->
     <!-- 处理不了的交给tomcat,也就是静态文件的映射 -->
  <mvc:default-servlet-handler/>

  <!-- 映射静态文件的路径 -->
    <mvc:resources location="/js/" mapping="/js/**"/>

  </beans>