基础接口开发讲解springWeb mvc + mysql + mybatis

最近从andriod转型后端开发,比较忙,所以有半年左右没有更新了,望大家见谅~

今天我就来讲一讲spring webMVC+msql的配置相关问题讲解

接口开发其实及其简单,任何java基础不错的同学,看了下面的文章分分钟就能写一个接口

准备工作如下:
开发工具:IDEA (注册码,http://idea.lanyus.com/)
数据库:MySQL(8.0版本的认证方式和与之前的版本发生了变化,时区也需要设置为GMT+8)
运行环境:tomcat(8.0+,9.0+都可以)
仓库:maven(maven3.0+)
http模拟:postman

有涉及开发环境问题,请留言

涉及到的第三方开源框架:springjavax.validationorg.hibernate.validatormybatismybatis-springmysql-connector-javacommons-dbcp2fastjsonaspectjweaverspring-jdbc

大家不用看到这么多的第三方框架就怕,其实它们各有各的关键特性,如果不想实现这些特性也可以不用引入。

spring:全局管理配置,依赖注入,aop等(整个项目的基础),具体请自行查阅资料,没有看过的童鞋也可以继续往下看一些基础设置,不难理解。
javax.validation:这个包主要是对参数进行验证并进行全局管理(具体用于接口入参判空、长度限制等)
org.hibernate.validator:这个包是具体实现,需配合javax.validation的出现
mybatis:简化数据库操作的类
mybatis-spring:mybatis的生命周期交由spring管理
mysql-connector-java:mysql的连接认证等,连接数据库必须,必须和pc的mysql版本对应,因为8.0认证方式发生了变更,如果使用低版本是无法连接到8.0+的数据库的(踩坑1)
spring-jdbc:数据库连接必须(踩坑2,一定要记得引入)
commons-dbcp2:数据源,有多种类型,这里选用dbcp2,
fastjson:处理json数据
aspectjweaver:aop必须的包

接下来看看项目的具体结构

在这里插入图片描述

req:request简写,主要存放接口请求参数相关类
rsp:response简写,主要存放返回参数相关类
CException:自定义的异常处理类
User:用户信息,字段名和数据库的字段名对应

controll包下存放所有的controller
ErrorController:用于处理全局异常
UserController:用户处理用户相关的控制

dao包:此包下的类负责提供数据,并操作数据库
mybatis包:此包下的接口主要用于和mapper文件映射,把sql操作的结果处理为标准的java结构

service包:控制器捕捉到url路径后,业务逻辑交由service层处理

resource/mybation/*.xml:此资源文件与java目录下的mybatis接口文件对应,支持sql语句,
resource/spring/application-context.xml:spring初始化的入口,在这完成初始化的配置
resource/spring/msql-context.xml:数据的配置文件(如数据库地址,用户名密码等)
webapp/WEB-INF/web.xml 可以理解为程序的入口,tomcat启动时读取的第一个配置文件

万事开头难,在看具体代码前,先梳理一下流程?第一,入口函数在哪?

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
     version="4.0">

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/application-context.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
    <servlet-name>servlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value></param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>

<servlet-mapping>
    <servlet-name>servlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

首先,先看一下目录结构中的webapp/WEB-INF/web.xml,这是tomcat启动时,读取的第一个配置文件,这就是我们整个程序的入口,下面就看看这个文件干了什么事情。

不难看出这是一个xml格式的文件,其中有4个节点,listener节点标识了一个监听事件,这里我们是用spring框架提供的类,这个类做的事情就是初始化context-param节点下的参数,这里我们的目的就是初始化spring。

servlet节点也定义了一个spring框架提供的servlet类,它的作用是拦截所有url请求,并分发到相应的控制器,

servlet-mapping节点中的url-pattern用于匹配地址,/ 表示匹配所有地址,通过servlet-name和servlet节点关联。

第二步,我们看看spring的初始化都干了什么事,路径如下,resource/spring/mc-application-context.xml,

<?xml version="1.0" encoding="UTF-8"?>
<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"
   xmlns="http://www.springframework.org/schema/beans"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context.xsd
   http://www.springframework.org/schema/mvc
   http://www.springframework.org/schema/mvc/spring-mvc.xsd">

// 扫描指定包的类
<context:component-scan base-package="com.ccy.demo"/>

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
		// 设置 控制器 支持 application/json格式的数据,默认是表单提交
            <property name="supportedMediaTypes">
                <list>
                    <value>application/json;charset=UTF-8</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

<import resource="mysql-context.xml"></import>

component-scan节点,作用是扫描指定包下的所有类,把@Controller @Service @Repository @Component 注解的类加入spring管理。

tips:这里补充一下这4个注解的说明,从功能来说,这4个注解是一样的,唯一的区别就在于对代码逻辑解耦,按照规范,我们在Controller层不做任何逻辑处理,只用来表示接口的入口,在Service中处理逻辑代码,在Repository层中处理数据的存取(简单来说就是和数据库的交互)。 这样任何一个service都可以从多个Repository中获取数据,实现的代码的解耦,Component用于标注功能不明确的类。简单来说这4个注解其实都可以用Component代替。另一个好处就是如果按照规范注解,当想要修改逻辑代码时就去service层寻找,想修改数据时就去Respoistory层寻找,达到快速定位的目的。

import resource节点,作用是导入其他指定的配置文件,这里我们导入了数据库的配置文件。

第三步,数据库配置

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://www.springframework.org/schema/beans"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd">

// 数据源配置,记得导入相应的包,否则tomcat或提示配置文件有错
<bean id="datasource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/mydb?serverTimezone=GMT%2B8"/>
    <property name="username" value="root"/>
    <property name="password" value="xsm520@ccy"/>
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="datasource"/>
    <property name="mapperLocations" value="classpath:mybatis/*.xml"/>
</bean>

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    <property name="basePackage" value="com.ccy.demo.dao.mybatis"/>
</bean>

有3个节点,
dateSource,指定数据源,指定数据库地址,指定用户名和密码。
sqlSession,指定mapper文件的位置,
mappeConfig,用于关联java文件和mapper文件的映射关系
这一步现在没看懂没关系,后面会具体讲解

流程清楚了,接下来就可以撸一撸代码了,大家可以想一想写接口的第一步应该是做什么操作,肯定是需要提供一个url地址让用户能访问,并能传递一些参数进入。

我们假设现在提供一个接口,让用户传入自己的基本信息,并保存到数据库,具体步骤如下
1.提供一个url地址让用户访问,如http://localhost/api/user/add,其中http://localhost/当发布到公网时,就是域名或ip,本地调试时,一般是http://localhost:8080/springweb_war_exploded/,有可能不同环境不一样,具体后面讲解。所以我们应该提供的完整访问地址是http://localhost:8080/springweb_war_exploded/api/user/add
2.提供一个add方法,此方法带有一个user的实体,包含用户基本信息
3.连接数据库
4.存入数据库
第一步,

@Controller
@RequestMapping(value = "api/user")
public class UserController {

// spring注入
@Autowired
private UserService mUserService;

@RequestMapping(value = "/add", method = RequestMethod.POST)
@ResponseBody
public AddUserRsp add(@RequestBody @Valid AddUserReq req) throws CException {
    return mUserService.add(req);
}

@RequestMapping(value = "/getAllUser", method = RequestMethod.POST)
@ResponseBody
public GetAllUserRsp getAllUser() throws CException {
    return mUserService.getAllUser();
}

@RequestMapping(value = "/getUser", method = RequestMethod.POST)
@ResponseBody
public GetUserRsp getUser(@RequestBody @Valid GetUserReq req) throws CException {
    return mUserService.getUser(req);
}
}

@Controller
@RequestMapping(value = “api/user”)
这2个注解表示了访问路径如下:api/user,从字面意思理解,并且这个类是一个controller

我们提供一个add方法,并提供一个user的入参,方法标注下一级路径/add,并设置访问方式为post,注意注解@ResponseBody和@RequestBody,某些情况下是可以缺省的,不过第一次,为了避免遇到奇怪的坑,建议加上,这里我们第一步就完成了。

这里我们的controller只做了一件事,接受到对应的请求后,把事情交由service层处理

第二部,接下来就进行逻辑操作,取出user中的姓名和年龄判断

注意这里的参数判断,如果每个接口都这样判断明显的会造成代码臃肿,这时候可以使用我刚刚提到的validation包,用于参数验证,修改后的代码如下:

package com.ccy.demo.bena.req;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

public class AddUserReq {

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

@NotNull(message = "age不能为空")
@Min(0)
@Max(150)
private Integer age;

public String getName() {
    return name;
}

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

public int getAge() {
    return age;
}

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

}

在user中的字段加上注解,表示name不能为null,并且age的范围应该在0-150之间,并在方法参数前加上注解@Valid,表示启用
在这里插入图片描述
第三步,连接数据库,首先确保电脑上已经安装mysql,并已经创建好数据库和表,确保已经引入相关包,数据库的连接信息已经在配置文件中申明了,如果能正常启动tomcat就表示已经连接成功

第四步,通过mybatis操作数据库,代码在dao/mybatis/UserBatis ,这个接口定义你想要的数据结构和查询参数,
spring会找到对应的mepper文件 执行sql语句

package com.ccy.demo.dao.mybatis;

import com.ccy.demo.bena.table.UserTo;
import org.apache.ibatis.annotations.Param;

import java.util.List;
// 可以理解为把数据库查询的数据转换为java结构的集合
public interface UserBatis {

//  注意注解@Param
void addUser(@Param("name") String name, @Param("age") int age) throws Exception;

List<UserTo> getAll() throws Exception;

UserTo getUser(@Param("name") String name) throws Exception;
}

与之对应的mapeer文件,注意id要与java文件的方法名一致,如果有返回数据需定义resultType,变量用#{key,type}表示,注意需与数据库定义的字段名保持一致

<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

// 对应的java文件 
<mapper namespace="com.ccy.demo.dao.mybatis.UserBatis">

<insert id="addUser">
    INSERT INTO t_users (`name`, age)
    VALUES (
    #{name, jdbcType=VARCHAR},
    #{age, jdbcType=INTEGER}
    )
</insert>

<select id="getAll" resultType="com.ccy.demo.bena.table.UserTo">
    select `name`,age from t_users
</select>

<select id="getUser" resultType="com.ccy.demo.bena.table.UserTo">
    select `name`,age from t_users where `name` = #{name, jdbcType=VARCHAR}
</select>

第五步,启动tomcat,用postman验证接口是否可以访问

插入用户
在这里插入图片描述

查询全部用户
在这里插入图片描述

查询单个用户
在这里插入图片描述
至此成功~

补充:全局异常捕获

ErrorController是用来捕获全局异常的,看看这个类都干了什么
@ControllerAdvice
public class ErrorController {

/**
 * Exception异常处理,表示系统错误
 *
 * @param ex
 */
@ResponseBody
@ExceptionHandler(value = Exception.class)
public ErrorRsp errHandler(Exception ex) {
    ErrorRsp rsp = new ErrorRsp();
    rsp.setErrorCode(ErrCodeUtils.SYSTEM_ERROR);
    rsp.setErrorMsg("system error");
    return rsp;
}

/**
 * CException异常处理,表示内部错误
 *
 * @param ex
 */
@ResponseBody
@ExceptionHandler(value = CException.class)
public ErrorRsp errHandler(CException ex) {
    ErrorRsp rsp = new ErrorRsp();
    rsp.setErrorCode(ErrCodeUtils.INTERNAL_ERROR);
    rsp.setErrorMsg("internal error");
    return rsp;
}

/**
 * MethodArgumentNotValidException异常处理,参数错误
 *
 * @param ex
 * @return
 */
@ResponseBody
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public ErrorRsp errHandler(MethodArgumentNotValidException ex) {

    StringBuilder stringBuilder = new StringBuilder();
    List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors();
    for (ObjectError error : objectErrors) {
        stringBuilder.append(error.getDefaultMessage());
        stringBuilder.append(",");
    }
    ErrorRsp rsp = new ErrorRsp();
    rsp.setErrorCode(ErrCodeUtils.PARAM_ERROR);
    rsp.setErrorMsg(stringBuilder.toString());
    return rsp;
}

}

看一下MethodArgumentNotValidException这个异常 就是上面提到的检验参数的异常,大家可以试一下如果在add接口传入错误参数,接口是怎么返回的

在这里插入图片描述

我后面完善后会把项目上传至github,敬请期待~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值