如何编写后端接口
一、接口的设计与规划
好的程序,一定有一套合理的后端接口。在设计后端接口的时候,要考虑清楚各个方面的需求,最好能有一个操作流程作为指导。
二、使用eclipse创建一个能够连接数据库的spring boot项目
打开eclipse,若没有插件,则安装。file->new->spring starter project->填写名称等基本信息->选则依赖(MySQL Driver,Spring Data Jpa,Spring Web)->完成
等程序运行完成(看右下角),就创建好了!
若是pom.xml文件第一行报错:Unknown,则将Spring Boot Version改小,可以改成2.1.4.RELEASE。
三、编写数据库连接,日志输出
将resource文件夹下的application.properties改成application.yml,并加入logback-spring.xml文件。
application.yml
server:
port: 8080
spring:
http:
encoding:
charset: utf8
enabled: true
force: true
jmx:
enabled: false
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/zuoshi?serverTimezone=GMT%2B8&characterEncoding=UTF-8
username:
password:
jpa:
database: MYSQL
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
hbm2ddl:
auto: update
hibernate:
ddl-auto: update
show-sql: true
##配置日志
logging:
# 日志配置文件
config: classpath:logback-spring.xml
# 日志path路径配置
path: ..\poem\logger
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 配置日志按天生成文件 S -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<Prudent>true</Prudent>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_PATH}/info-%d{yyyy-MM-dd}.log </FileNamePattern>
<MaxHistory>60</MaxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern> %d{yyyy-MM-dd HH:mm:ss} -%msg%n </Pattern>
</layout>
</appender>
<!-- 配置日志按天生成文件 E -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%date %-5level [%thread] %logger{100}[%line] - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.gome" level="INFO"/>
<logger name="org.apache" level="WARN"/>
<logger name="com.alibaba" level="INFO"/>
<logger name="com.alibaba.dubbo" level="INFO"/>
<logger name="org.springframework.web" level="INFO"/>
<logger name="org.springframework.test" level="INFO"/>
<logger name="org.springframework.boot" level="INFO"/>
<logger name="org.springframework" level="INFO"/>
<logger name="jdbc" level="WARN"/>
<logger name="jdbc.sqltiming" level="DEBUG"/>
<logger name="org.mybatis" level="WARN"/>
<logger name="org.spring.jdbc" level="WARN"/>
<!--
其中appender的配置表示打印到控制台(稍后详细讲解appender );
<root level="INFO">将root的打印级别设置为“INFO”,指定了名字为“STDOUT”的appender。
-->
<root level="INFO">
<appender-ref ref="FILE"/>
<appender-ref ref="STDOUT"/>
</root>
</configuration>
四、编写entity(关联数据库的类)
每个entity对应数据库里的一张表,注意在类头上添加注解:@Entity,@Table(name=“entity”),每个属性对应一个字段,主键上添加注解:@Id,@GeneratedValue(strategy = GenerationType.IDENTITY),文本类型属性添加注解:@Column(name = “user_pwd”, nullable = false, length = 20),boolean类型属性,添加注解:@Column(name = “is_delete”, nullable = false),时间类型属性添加注解:@Column(name = “create_time”,nullable = false)@Temporal(TemporalType.TIMESTAMP)。
五、编写repository(数据库查询接口)
repository是一个很好用的,查询数据库的接口。注意在类头上写上注解:@Repository,@Transactional。只要按照命名规范去写,这个接口就不需要实现,可以直接调用。有三个函数特别管用(注意该类的继承关系):
@Repository
@Transactional
public interface ArticleRepository extends JpaRepository<Article, Integer>{
Optional<Article> findById(Integer id);//按照主键查找
void deleteById(Integer id);//按照主键删除
@SuppressWarnings("unchecked")
Article saveAndFlush(Article article);//保存并更新
}
六、编写service(服务层的接口)
服务层直接和数据层交互,可以把一些元操作变成接口,以便控制层调用。
七、编写serviceimpl(服务层接口的实现)
注意类头上的注解:@Service,既然是接口的实现,那么,需要implements接口,然后将接口里的函数引入。声明一个repository的实例,并且加上注解:@Autowired,加上如下的代码:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
public Session getSession() {
Configuration cfg = new Configuration();
cfg.configure("/hibernate.cfg.xml");
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder();
builder.applySettings(cfg.getProperties());
SessionFactory factory = cfg.buildSessionFactory(builder.build());
return factory.openSession();
}
接下来使用hql语法进行数据库的操作:
Session session = getSession();
String hql = "select count(*) from Article where titleId = :index";
Query query = session.createQuery(hql).setParameter("index", bookId);
Integer count = (Integer) query.uniqueResult();
String hqltwo = "update Article set chapterId = chapterId + 1 where chapterId >= :first and chapterId < last and titleId = :bookId";
session.createQuery(hqltwo).setParameter("first", chapterId).setParameter("last", count).setParameter("bookId", bookId);
八、编写controller(暴露给用户使用的接口,实际是一个类)
类头上写上注解和接口路径:@RestController,@RequestMapping("/rest/article"),每个方法上方,写上接口路径注解和返回JSON格式的注解:@RequestMapping("/throughArticle"),
@ResponseBody,注意创建一个serviceimpl的实例,加上@Autowired注解;
九、关于异常捕获
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
@ResponseBody
public class myException {
//1登录失败2读取失败3创建失败4修改失败5加载失败6加入失败7删除失败8返回失败9请重新登录
private String NullPointerExceptionStr="空指针异常";
private String ArrayIndexOutOfBoundsStr="数组越界异常";
private String ClassCastExceptionStr="类型转换异常";
private int ERROR_CODE = 400;
static Logger logger = LoggerFactory.getLogger(myException.class);
//空指针异常
@ExceptionHandler(NullPointerException.class)
public ReturnData nullPointerExceptionHandler(NullPointerException ex) {
return resultFormat(ERROR_CODE, new Exception(NullPointerExceptionStr));
}
//类型转换异常
@ExceptionHandler(ClassCastException.class)
public ReturnData classCastExceptionHandler(ClassCastException ex) {
return resultFormat(ERROR_CODE, new Exception(ClassCastExceptionStr));
}
//数组越界异常
@ExceptionHandler(ArrayIndexOutOfBoundsException.class)
public ReturnData ArrayIndexOutOfBoundsException(ArrayIndexOutOfBoundsException ex) {
return resultFormat(ERROR_CODE, new Exception(ArrayIndexOutOfBoundsStr));
}
//其他错误
@ExceptionHandler({Exception.class})
public ReturnData exception(Exception ex) {
ex.printStackTrace();
logger.info(ex.getMessage());
return resultFormat(ERROR_CODE, new Exception(ResponseCode.SYSTEMBUSY.getMsg()));
}
//自定义错误
public static ReturnData toException(Integer code, String msg) {
logger.info(msg);
return ReturnData.build(code, msg);
}
private <T extends Throwable> ReturnData resultFormat(Integer code, T ex) {
ex.printStackTrace();
return ReturnData.build(code, ex.getMessage());
}
}
其中,ReturnData 是自定义的数据存储输出类。
十、关于跨域的问题
新增加config路径,写过滤器:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class MyInterceptor extends HandlerInterceptorAdapter{
static Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,Content-Type");
response.setHeader("Access-Control-Max-Age", "3600");
System.err.println("------------------>:已完成跨域处理");
logger.info("已完成跨域处理!");
return true;
}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyWebConfigurer implements WebMvcConfigurer{
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**");
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
在controller类头上加上跨域注解:@CrossOrigin。
十一、数据的传递
自定义的数据传递类,需要包含三个部分:
一、执行结果状态;
二、执行结果状态描述;
三、执行结果(Object类型);
十二、服务器上tomcat的设置
1、如何使用域名访问网站?
(1)config->server.xml更改:把8080端口改成80;
(2)修改
<Engine name="Catalina" defaultHost="localhost">
为
<Engine name="Catalina" defaultHost="www.test.com">
(3)找到host标签,修改为:
<Host name="www.test.com" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context path="" docBase="xxxx"/><!--xxxx就是在webapps下面xxxx.war的名字-->
<Alias>test.com</Alias><!--如果没带www域名也配置好映射了就加上这个-->
(4)重启tomcat服务;
2、一个tomcat部署多个项目
(1)tomcat路径下,新建一个文件夹,以区别于webapps文件夹,用于存放第二个项目;
(2)server.xml里,加入一个新的Service(可以拷贝后修改参数);
(3)注意:两个项目不能使用同一个端口,项目存放的文件夹需要修改;
十三、利用tomcat部署程序到服务器上
spring boot项目打包成war包:
(1)pom.xml里边配置:
<packaging>war</packaging>;
(2)pom.xml里边,撤销嵌入的tomcat:在web的dependency下边:
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
(3)添加servlet依赖:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
(4)添加SpringBootApplication启动类:
/**
* 修改启动类,继承 SpringBootServletInitializer 并重写 configure 方法
*/
public class SpringBootStartApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
// 注意这里要指向原先用main方法执行的Application启动类
return builder.sources(Application.class);
}
}
(5)右键工程:Run as->Maven build…->Goals里边填上:clean package->确定;
(6)在target文件夹下能找到打包好的war包;
十四、运行程序
去掉war包的后缀(工程名.war),放到部署好的文件夹下边(一般为webapps),启动tomcat就好了。
十五、几个eclipse的使用技巧
1、自动提示的设置
26个字母不用区分大小写。
2、自动注释的设置
通过Alt+Shift+J自动添加注释。
3、@GeneratedValue注解
strategy属性提供四种值:
AUTO主键由程序控制, 是默认选项 ,不设置就是这个;
IDENTITY 主键由数据库生成, 采用数据库自增长, Oracle不支持这种方式;
SEQUENCE 通过数据库的序列产生主键, MYSQL 不支持;
Table 提供特定的数据库产生主键, 该方式更有利于数据库的移植。
4、打开数据库的几种方式
ddl-auto:create:每次运行该程序,没有表格会新建表格,表内有数据会清空
ddl-auto:create-drop:每次程序结束的时候会清空表
ddl-auto:update:每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新
ddl-auto:validate:运行程序会校验数据与数据库的字段类型是否相同,不同会报错
5、@Controller与@RestController
Controller可以返回网页,RestController返回的是数据。
6、网页接口与后端接口的区别
网页接口需要使用thymleaf模板,引入如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
后端接口则直接使用POSTMAN访问测试。
7、@ResponseBody
让结果类按照JSON字符串的形式返回。
十六、eclipse常见问题
1、系统找不到menifest.mf:找到xmlns中间的空格,先回车,再复原,就好了。
2、eclipse自动生成get和set:右键->source->Generate Getters and Setters…
3、org.springframework包报错:
pom.xml里边加入:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
4、Archive for required library: “xxxx” in project ‘*’ cannot be read or is not a valid ZIP file:删除路径下的整个文件夹,然后项目右键->Run as->Maven Install,最后update项目。
5、spring boot数据库:关键字,如user,limit,delete等,不能作为表名,字段名或者出现在需要自定义的地方;