继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

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

程序员大阳
关注TA
已关注
手记 357
粉丝 1.5万
获赞 1523

背景

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

新建项目

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

Project name:restfulblog

勾选Generate web.xml deployment descriptor

导入jar包

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

注意Spring Restful请求都是返回json字符串,所以需要添加转换json的jar包,同时因为要访问数据库,所以添加mysql数据链接的jar包:
在这里插入图片描述
后续不再逐一提供jar包下载地址,给大家一个可以搜索的jar包仓库,自行下载吧:https://mvnrepository.com/

修改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>

新建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>

添加数据库操作类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) {
				// 此处应打印日志
			}
		}
	}
}

添加博客服务类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);
		}
	}
}

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);
	}
}

浏览器简单测试

由于浏览器地址栏直接输入的请求是get类型的,所以我们可简单的从浏览器测试下查询博客信息,打开谷歌浏览器,访问http://127.0.0.1:8080/restfulblog/blog/1,返回如下信息:
在这里插入图片描述
可见已成功返回json字符串。

总结

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

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

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP