Spring之路(25)–Spring Restful+jQuery+Bootstrap开发博客系统实例(API后端开发篇)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 本文目录1. 背景2. 新建项目3. 导入jar包4. 修改web.xml加载spring配置5. 新建springmvc-config.xml,配置容器信息6. 添加数据库操作类DbHelper7. 添加博客服务类BlogService与数据对象BlogBo8. BlogController实现Restful API9. 浏览器简单测试10.总结

1. 背景

本篇将之前实现过的博客系统的后端api改为Spring Restful风格,虽然说是修改,但实际上还是从头到尾实现一下子。


2. 新建项目

打开eclipse,File-New-Other-Dynamic Web Project。


Project name:restfulblog


勾选Generate web.xml deployment descriptor


3. 导入jar包

将之前一直在用的jar包拷贝到WEB-INF/lib目录下。


注意Spring Restful请求都是返回json字符串,所以需要添加转换json的jar包,同时因为要访问数据库,所以添加mysql数据链接的jar包:

image.png

后续不再逐一提供jar包下载地址,给大家一个可以搜索的jar包仓库,自行下载吧:https://mvnrepository.com/


4. 修改web.xml加载spring配置

修改web.xml如下,该配置文件配置了DispatcherServlet,同时指定了容器使用的配置文件springmvc-config.xml。


注意<url-pattern>/*</url-pattern>表示匹配所有请求,此时不再限制请求路径以.do结尾,因为跟restful风格不符合了。


<?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_3_1.xsd"

id="WebApp_ID" version="3.1">

<display-name>restfulblog</display-name>

<servlet>

 <servlet-name>springmvc</servlet-name>

 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

 <init-param>

  <param-name>contextConfigLocation</param-name>

  <param-value>/WEB-INF/springmvc-config.xml</param-value>

 </init-param>

 <load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

 <servlet-name>springmvc</servlet-name>

 <url-pattern>/*</url-pattern>

</servlet-mapping>

</web-app>


5. 新建springmvc-config.xml,配置容器信息

在WEB/INF下新建springmvc-config.xml,添加对容器的配置,主要是开启bean自动扫描。另外开启了新的注解<mvc:annotation-driven />为MVC提供额外的支持。


<?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-4.0.xsd

       http://www.springframework.org/schema/context

       http://www.springframework.org/schema/context/spring-context-4.0.xsd

       http://www.springframework.org/schema/mvc

       http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

<!-- 指定扫描的包 -->

<context:component-scan

 base-package="org.maoge.restfulblog" />

<!--注解驱动,开启通过注解配置访问路径与方法的匹配 -->

<mvc:annotation-driven />

</beans>


6. 添加数据库操作类DbHelper

注意此处我们还是使用myblog数据库,不再新建数据库了,所以url依然为jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8


然后注意我们将@Component改为了@Repository,@Repository也是将DbHelper注册为bean,但是它用于持久层上,更加能表明bean的类型,一般跟持久层相关的bean使用@Repository。OK,代码如下:


package org.maoge.restfulblog;

import java.sql.Connection;

import java.sql.DriverManager;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Repository;

//@Component

@Repository//替代@Component

public class DbHelper {

@Value("com.mysql.jdbc.Driver") // 注入driver属性

private String driver;

@Value("jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8") // 注入数据库url属性

private String url;

@Value("root") // 注入用户名属性

private String username;

@Value("XXX") // 注入密码属性

private String password;

/**

 * 初始化

 */

@PostConstruct // 使用该注解,以便在项目启动时执行数据库驱动加载工作

public void init() {

 try {

  Class.forName(driver);

 } catch (Exception e) {

  // 此处应打印日志

 }

}

/**

 * 获取数据库连接

 */

public Connection getConnection() {

 Connection conn = null;

 try {

  conn = DriverManager.getConnection(url, username, password);

 } catch (Exception e) {

  // 此处应打印日志

 }

 return conn;

}

/**

 * 关闭数据库连接

 */

public void closeConnection(Connection conn) {

 if(conn!=null) {

  try {

   conn.close();

  }catch(Exception e) {

   // 此处应打印日志

  }

 }

}

}


7. 添加博客服务类BlogService与数据对象BlogBo

注意博客服务类的注解,我们将@Component改为了@Service,这个道理同上,@Service用来描述服务层(业务层)的bean。具体代码如下:


package org.maoge.restfulblog;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.util.ArrayList;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

/**

* @theme 服务--博客

* @author maoge

* @date 2020-01-27

*/

//@Component

@Service//替代@Component

public class BlogService {

@Autowired // 自动注入dbHelper组件

private DbHelper dbHelper;

/**

 * 获取博客列表

 */

public List<BlogDo> getBlogList() {

 List<BlogDo> blogList = new ArrayList<BlogDo>();

 Connection conn = null;

 try {

  conn = dbHelper.getConnection();

  String sql = "select * from blog";

  PreparedStatement stmt = conn.prepareStatement(sql);

  ResultSet rs = stmt.executeQuery();

  while (rs.next()) {

   BlogDo blog = new BlogDo();

   blogList.add(blog);

   blog.setAuthor(rs.getString("author"));

   blog.setContent(rs.getString("content"));

   blog.setId(rs.getLong("id"));

   blog.setTitle(rs.getString("title"));

  }

 } catch (Exception e) {

  // 此处应打印日志

 } finally {

  dbHelper.closeConnection(conn);

 }

 return blogList;

}

/**

 * 按id获取博客信息

 */

public BlogDo getBlogById(Long id) {

 BlogDo blog=null;

 Connection conn = null;

 try {

  conn = dbHelper.getConnection();

  String sql = "select * from blog where id=?";

  PreparedStatement stmt = conn.prepareStatement(sql);

  stmt.setLong(1, id);

  ResultSet rs = stmt.executeQuery();

  if (rs.next()) {

   blog=new BlogDo();

   blog.setAuthor(rs.getString("author"));

   blog.setContent(rs.getString("content"));

   blog.setId(rs.getLong("id"));

   blog.setTitle(rs.getString("title"));

  }

 } catch (Exception e) {

  // 此处应打印日志

 } finally {

  dbHelper.closeConnection(conn);

 }

 return blog;

}

/**

 * 新增博客

 */

public int addBlog(BlogDo blog) {

 Connection conn = null;

 try {

  conn = dbHelper.getConnection();

  String sql = "insert into blog(author,content,title)values(?,?,?)";

  PreparedStatement stmt = conn.prepareStatement(sql);

  stmt.setString(1, blog.getAuthor());

  stmt.setString(2, blog.getContent());

  stmt.setString(3, blog.getTitle());

  return stmt.executeUpdate();

 } catch (Exception e) {

  // 此处应打印日志

  return 0;

 } finally {

  dbHelper.closeConnection(conn);

 }

}

/**

 * 根据博客id更新博客信息

 */

public int updateBlog(BlogDo blog) {

 Connection conn = null;

 try {

  conn = dbHelper.getConnection();

  String sql = "update blog set author=?,content=?,title=? where id=?";

  PreparedStatement stmt = conn.prepareStatement(sql);

  stmt.setString(1, blog.getAuthor());

  stmt.setString(2, blog.getContent());

  stmt.setString(3, blog.getTitle());

  stmt.setLong(4, blog.getId());

  return stmt.executeUpdate();

 } catch (Exception e) {

  // 此处应打印日志

  return 0;

 } finally {

  dbHelper.closeConnection(conn);

 }

}

/**

 * 根据博客id删除对应博客

 */

public int deleteBlog(Long id) {

 Connection conn = null;

 try {

  conn = dbHelper.getConnection();

  String sql = "delete from blog where id=?";

  PreparedStatement stmt = conn.prepareStatement(sql);

  stmt.setLong(1, id);

  return stmt.executeUpdate();

 } catch (Exception e) {

  // 此处应打印日志

  return 0;

 } finally {

  dbHelper.closeConnection(conn);

 }

}

}


8. BlogController实现Restful API

重点来了,之前的控制器中,我们返回的都是网页,而在Restful的风格下,我们需要返回json。


SpringMVC可以通过对方法添加@ResponseBody注解,将返回的对象转换为json,完事了!就是这么简单,这就是极简的设计理念,完美。还可以更加简单,如果一个控制器中提供的都是Restful API方法,则可以直接将@Controller改写为@RestController,这样控制下所有API方法返回的对象都会被自动转换为json,比简单还简单,追求极致。


下面具体实现下,注意下注释:


package org.maoge.restfulblog;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.DeleteMapping;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.PutMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RestController;

/**

* @theme 控制器--博客

* @author maoge

* @date 2020-01-28

*/

@RestController // 通过该注解,第一将BlogController注册为控制器,第二将其中方法返回值转换为json

public class BlogController {

@Autowired // 自动装配blogService

private BlogService blogService;

/**

 * 查询博客信息

 * 1、@GetMapping表示可以使用get方法请求该api

 * 2、"/blog/{id}"表示请求路径为/blog/{id}的形式,其中{id}为占位符

 * 3、@PathVariable("id")表示将占位符{id}的值传递给id

 * 4、也就是说/blog/123请求的话,会将123传递给参数id

 */

@GetMapping("/blog/{id}")

public BlogDo getOne(@PathVariable("id") long id) {

 return blogService.getBlogById(id);

}

/**

 * 查询博客列表,使用get方法

 */

@GetMapping("/blog")

public List<BlogDo> getList(){

 return blogService.getBlogList();

}

/**

 * 新增博客

 * 1、@PostMapping表示使用post方法

 * 2、@RequestBody表示将请求中的json信息转换为BlogDo类型的对象信息,该转换也是由SpringMVC自动完成的

 */

@PostMapping("/blog")

public void add(@RequestBody BlogDo blog) {

 blogService.addBlog(blog);

}

/**

 * 修改博客

 * 实际上此处也可以不在路径中传递id,而是整个使用json传递对象信息,但是我查询了一些文档,貌似使用路径传递id更加规范一些,此处不用纠结

 */

@PutMapping("/blog/{id}")

public void update(@PathVariable("id") long id,@RequestBody BlogDo blog) {

 //修改指定id的博客信息

 blog.setId(id);

 blogService.updateBlog(blog);

}

/**

 * 删除博客

 */

@DeleteMapping("/blog/{id}")

public void delete(@PathVariable("id") long id) {

 blogService.deleteBlog(id);

}

}


9. 浏览器简单测试

由于浏览器地址栏直接输入的请求是get类型的,所以我们可简单的从浏览器测试下查询博客信息,打开谷歌浏览器,访问http://127.0.0.1:8080/restfulblog/blog/1,返回如下信息:image.png

可见已成功返回json字符串。

10.总结

当后端可以提供规范的API,以restful风格提供服务接口,而返回值采用规范的json格式,是一个巨大的提高。

后续我们可以采用这种风格来开发web应用,前端负责界面渲染操作交互,后端提供API接口,前后端分离,更加优雅高效。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
18小时前
|
API 数据安全/隐私保护 UED
探索鸿蒙的蓝牙A2DP与访问API:从学习到实现的开发之旅
在掌握了鸿蒙系统的开发基础后,我挑战了蓝牙功能的开发。通过Bluetooth A2DP和Access API,实现了蓝牙音频流传输、设备连接和权限管理。具体步骤包括:理解API作用、配置环境与权限、扫描并连接设备、实现音频流控制及动态切换设备。最终,我构建了一个简单的蓝牙音频播放器,具备设备扫描、连接、音频播放与停止、切换输出设备等功能。这次开发让我对蓝牙技术有了更深的理解,也为未来的复杂项目打下了坚实的基础。
77 58
探索鸿蒙的蓝牙A2DP与访问API:从学习到实现的开发之旅
|
7天前
|
监控 供应链 搜索推荐
阿里妈妈商品详情API接口:开发、应用与收益的深度剖析
阿里妈妈是阿里巴巴旗下的数字营销平台,其商品详情API接口为开发者提供了获取淘宝、天猫等电商平台商品详细信息的工具。本文介绍了该接口的开发流程、应用场景及带来的收益,揭示了其在电商生态中的重要地位。
54 6
|
7天前
|
供应链 搜索推荐 API
1688APP原数据API接口的开发、应用与收益(一篇文章全明白)
1688作为全球知名的B2B电商平台,通过开放的原数据API接口,为开发者提供了丰富的数据资源,涵盖商品信息、交易数据、店铺信息、物流信息和用户信息等。本文将深入探讨1688 APP原数据API接口的开发、应用及其带来的商业收益,包括提升流量、优化库存管理、增强用户体验等方面。
41 6
|
8天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
36 3
|
9天前
|
监控 搜索推荐 API
京东商品详情API接口的开发、应用与收益探索
在数字化和互联网高速发展的时代,京东通过开放商品详情API接口,为开发者、企业和商家提供了丰富的数据源和创新空间。本文将探讨该API接口的开发背景、流程、应用场景及带来的多重收益,包括促进生态系统建设、提升数据利用效率和推动数字化转型等。
32 3
|
14天前
|
供应链 搜索推荐 API
探索1688榜单商品详细信息API接口:开发、应用与收益
本文深入探讨了1688榜单商品详细信息API接口的开发与应用,涵盖接口概述、开发条件、调用方法及数据处理等内容。该API帮助企业高效获取1688平台商品信息,应用于商品信息采集、校验、同步与数据分析等领域,有效提升了企业的运营效率、库存管理、销售转化率及市场策略制定能力,降低了采购成本,提升了客户满意度。
37 9
|
3天前
|
存储 搜索推荐 API
小红书笔记详情API接口的开发、应用与收益
小红书笔记详情API接口为开发者、企业和内容创作者提供了获取平台丰富资源的通道。通过该接口,用户可以提取笔记的详细信息(如标题、正文、标签等),并应用于市场调研、竞品分析、内容创作、电商推荐等多个领域。这不仅有助于提升品牌影响力和优化用户体验,还能挖掘商业机会,促进内容创新,增强用户互动与社群凝聚力。总之,小红书笔记详情API接口为企业和个人在社交媒体领域探索新增长点提供了重要工具。
18 0
|
17天前
|
存储 缓存 负载均衡
后端开发中的性能优化策略
本文将探讨几种常见的后端性能优化策略,包括代码层面的优化、数据库查询优化、缓存机制的应用以及负载均衡的实现。通过这些方法,开发者可以显著提升系统的响应速度和处理能力,从而提供更好的用户体验。
44 4
|
23天前
|
存储 前端开发 Java
深入理解后端开发:从基础到高级
本文将带你走进后端开发的神秘世界,从基础概念到高级应用,一步步揭示后端开发的全貌。我们将通过代码示例,让你更好地理解和掌握后端开发的核心技能。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供有价值的信息和启示。
|
26天前
|
存储 缓存 监控
后端开发中的缓存机制:深度解析与最佳实践####
本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####