Spring MVC:带有CNVR卷的REST应用程序。 1个

不久前,我阅读了Paul Chapman撰写的有关内容协商视图解析器 (CNVR)的文章。 Spring Framework Blog上的那篇文章启发了我研究这个框架的领域。 因此,我开发了一个基于Spring MVC和CNVR的 REST示例应用程序。 该应用程序演示了REST服务的基本流程-实体的创建,删除,读取和版本。

Spring Framework很长时间以来都支持REST服务,您可以更早地使用Message Converters开发一些服务。 在Spring 3.2中,所有这些东西在配置和开发中变得更加容易。 因此,让我们停止交谈,因为我将展示带有CNVR的Spring REST服务的基本设置和开发。

CNVR的基本思想是,根据CNVR从客户端请求中获取的信息,定义资源的哪种表示形式回馈给客户端。 您可以问我:请求中可影响CNVR决策的信息是什么? 答案很简单:

  • 网址后缀(例如.xml,.json,.html等
  • URL参数(默认格式
  • HTTP Accept标头属性

这是高级CNVR工作流程的图示:

Spring-MVC-CNVR模式

有关更多信息,我建议阅读Paul Chapman的完整文章。

使用CNVR设置Spring MVC REST项目

我将与一个Maven项目一起工作,一如既往,我将提供一个指向项目的GitHub存储库的链接。 这是整个项目的屏幕截图:

CNVR项目

我已经多次解释了如何在Eclipse中设置Dynamic Web Project,因此现在我仅提供带有一些简短说明的源文件。 您可以在下面找到所需的Maven依赖项:

<properties><mysql.connector>5.1.25</mysql.connector><hibernate.version>4.2.3.Final</hibernate.version><spring.version>3.2.3.RELEASE</spring.version><spring.data.version>1.3.2.RELEASE</spring.data.version><jackson.version>1.9.12</jackson.version></properties><dependencies><!-- DataBase libs --><dependency><groupid>mysql</groupid><artifactid>mysql-connector-java</artifactid><version>${mysql.connector}</version></dependency><dependency><groupid>commons-dbcp</groupid><artifactid>commons-dbcp</artifactid><version>1.4</version></dependency><!-- Hibernate --><dependency><groupid>org.hibernate</groupid><artifactid>hibernate-core</artifactid><version>${hibernate.version}</version></dependency><dependency><groupid>org.hibernate</groupid><artifactid>hibernate-entitymanager</artifactid><version>${hibernate.version}</version></dependency><!-- Spring --><dependency><groupid>org.springframework</groupid><artifactid>spring-webmvc</artifactid><version>${spring.version}</version></dependency><dependency><groupid>org.springframework.data</groupid><artifactid>spring-data-jpa</artifactid><version>${spring.data.version}</version><exclusions><exclusion><artifactid>spring-aop</artifactid><groupid>org.springframework</groupid></exclusion></exclusions></dependency><dependency><groupid>org.springframework</groupid><artifactid>spring-orm</artifactid><version>${spring.version}</version></dependency><dependency><groupid>org.springframework</groupid><artifactid>spring-tx</artifactid><version>${spring.version}</version></dependency><!-- CGLIB is required to process @Configuration classes --><dependency><groupid>cglib</groupid><artifactid>cglib</artifactid><version>3.0</version></dependency><!-- Other --><dependency><groupid>javax.servlet</groupid><artifactid>javax.servlet-api</artifactid><version>3.0.1</version><scope>provided</scope></dependency><dependency><groupid>jstl</groupid><artifactid>jstl</artifactid><version>1.2</version></dependency><!-- CNVR resources --><dependency><groupid>org.codehaus.jackson</groupid><artifactid>jackson-mapper-asl</artifactid><version>${jackson.version}</version></dependency></dependencies>

您可以在GitHub上找到pom.xml文件的完整版本。 因此,让我们继续进行准备。 我将使用MySQL作为数据库。 我需要在其中创建一个下表:

CREATE TABLE `smartphones` (`id` int(6) NOT NULL AUTO_INCREMENT,`producer` varchar(20) NOT NULL,`model` varchar(20) NOT NULL,`price` double NOT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;

现在我们需要适当的java对象,它将代表智能手机表:

@Entity
@Table(name="smartphones")
public class Smartphone {@Id@GeneratedValueprivate Integer id;private String producer;private String model;private double price;/*** Method updates already existed {@link Smartphone} object with values from the inputed argument.* @param sPhone - Object which contains new Smartphone values.* @return {@link Smartphone} object to which this method applied.*/public Smartphone update(Smartphone sPhone) {this.producer = sPhone.producer;this.model = sPhone.model;this.price = sPhone.price;return this;}@Overridepublic String toString() {return producer+": "+model+" with price "+price;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getProducer() {return producer;}public void setProducer(String producer) {this.producer = producer;}public String getModel() {return model;}public void setModel(String model) {this.model = model;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}}

准备工作大部分完成。 服务和DAO层是我需要做的最后一件事。 我将使用Spring Data作为DAO层,在我以前的一篇文章中,我对它的设置进行了详细的回顾。

public interface SmartphoneRepository extends JpaRepository< Smartphone, Integer >{ }

这里是对应的服务接口及其实现:

public interface SmartphoneService {public Smartphone create(Smartphone sp);public Smartphone get(Integer id);public List< Smartphone > getAll();public Smartphone update(Smartphone sp) throws SmartphoneNotFoundException;public Smartphone delete(Integer id) throws SmartphoneNotFoundException;}

服务实施:

@Service
@Transactional(rollbackFor=SmartphoneNotFoundException.class)
public class SmartphoneServiceImpl implements SmartphoneService {@Autowiredprivate SmartphoneRepository smartphoneRepository;@Overridepublic Smartphone create(Smartphone sp) {return smartphoneRepository.save(sp);}@Overridepublic Smartphone get(Integer id) {return smartphoneRepository.findOne(id);}@Overridepublic List< Smartphone > getAll() {return smartphoneRepository.findAll();}@Overridepublic Smartphone update(Smartphone sp) throws SmartphoneNotFoundException {Smartphone sPhoneToUpdate = get(sp.getId());if (sPhoneToUpdate == null)throw new SmartphoneNotFoundException(sp.getId().toString());sPhoneToUpdate.update(sp);return sPhoneToUpdate;}@Overridepublic Smartphone delete(Integer id) throws SmartphoneNotFoundException {Smartphone sPhone = get(id);if (sPhone == null)throw new SmartphoneNotFoundException(id.toString());smartphoneRepository.delete(id);return sPhone;}
}

在项目设置的最后,让我们考虑配置的“核心”: InitializerWebAppConfig文件。

@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan("com.mobapp")
@PropertySource("classpath:application.properties")
@EnableJpaRepositories("com.mobapp.repository")
public class WebAppConfig extends WebMvcConfigurerAdapter {private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";private static final String PROPERTY_NAME_DATABASE_URL = "db.url";private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";@Resourceprivate Environment env;@Beanpublic DataSource dataSource() {DriverManagerDataSource dataSource = new DriverManagerDataSource();dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));return dataSource;}@Beanpublic LocalContainerEntityManagerFactoryBean entityManagerFactory() {LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();entityManagerFactoryBean.setDataSource(dataSource());entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);entityManagerFactoryBean.
setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));entityManagerFactoryBean.setJpaProperties(hibProperties());return entityManagerFactoryBean;}private Properties hibProperties() {Properties properties = new Properties();properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));return properties;	}@Beanpublic JpaTransactionManager transactionManager() {JpaTransactionManager transactionManager = new JpaTransactionManager();transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());return transactionManager;}@Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.favorPathExtension(true).useJaf(false).ignoreAcceptHeader(true).mediaType("html", MediaType.TEXT_HTML).mediaType("json", MediaType.APPLICATION_JSON).defaultContentType(MediaType.TEXT_HTML);}@Beanpublic ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {List< ViewResolver > resolvers = new ArrayList< ViewResolver >();InternalResourceViewResolver r1 = new InternalResourceViewResolver();r1.setPrefix("/WEB-INF/pages/");r1.setSuffix(".jsp");r1.setViewClass(JstlView.class);resolvers.add(r1);JsonViewResolver r2 = new JsonViewResolver();resolvers.add(r2);ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();resolver.setViewResolvers(resolvers);resolver.setContentNegotiationManager(manager);return resolver;}/*** View resolver for returning JSON in a view-based system. Always returns a* {@link MappingJacksonJsonView}.*/public class JsonViewResolver implements ViewResolver {public View resolveViewName(String viewName, Locale locale)throws Exception {MappingJacksonJsonView view = new MappingJacksonJsonView();view.setPrettyPrint(true);return view;}}}

尽管文件足够大,但我只想将您的注意力集中在几件事上。 第一个是JsonViewResolver内部类。 处理JSON请求是必需的。 当然,可以将其与WebAppConfig类分开声明,也可以将其导入其中。 但是我决定将其直接放在WebAppConfig中,以避免分散注意力。 第二个是configureContentNegotiation方法。 在这里,我为内容协商视图解析器设置了选项。 最后,在contentNegotiatingViewResolver bean中,我确定了哪些视图解析器将在我的应用程序中可用。

public class Initializer implements WebApplicationInitializer {private static final String DISPATCHER_SERVLET_NAME = "dispatcher";@Overridepublic void onStartup(ServletContext servletContext) throws ServletException {AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();ctx.register(WebAppConfig.class);ctx.setServletContext(servletContext);		registerHiddenHttpMethodFilter(servletContext);	Dynamic servlet = servletContext.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(ctx));servlet.addMapping("/");servlet.setLoadOnStartup(1);}private void registerHiddenHttpMethodFilter(ServletContext servletContext) {FilterRegistration.Dynamic fr = servletContext.addFilter("hiddenHttpMethodFilter", HiddenHttpMethodFilter.class);fr.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD), false, DISPATCHER_SERVLET_NAME);}}

在Initializer类中,本教程仅涉及一件事。 它是registerHiddenHttpMethodFilter方法。 此方法将有助于处理诸如PUT和DELETE之类的HTTP方法。

希望您不要感到疲倦,因为最有趣的内容将在本教程的以下部分等您。

参考: Spring MVC:具有CNVR卷的REST应用程序。 Fruzenshtein的笔记博客中来自JCG合作伙伴 Alexey Zvolinskiy的1 。

翻译自: https://www.javacodegeeks.com/2013/07/spring-mvc-rest-application-with-cnvr-vol-1.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366996.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《精通Spring 4.x 企业应用开发实战》学习笔记

第四章 IoC容器 4.1 IoC概述 IoC&#xff08;Inverse of Control 控制反转&#xff09;&#xff0c;控制是指接口实现类的选择控制权&#xff0c;反转是指这种选择控制权从调用类转移到外部第三方类或容器的手中。 也就是由Spring容器借由Bean配置来进行控制。 DI&#xff08;D…

微前端——无界wujie

B站课程视频 课程视频 课程课件笔记&#xff1a; 1.微前端 2.无界 现有的微前端框架&#xff1a;iframe、qiankun、Micro-app&#xff08;京东&#xff09;、EMP&#xff08;百度&#xff09;、无届 前置 初始化 新建一个文件夹 1.通过npm i typescript -g安装ts 2.然后可…

java executor spring_Spring+TaskExecutor实例

一 TaskExecutor接口Spring的TaskExecutor接口等同于Java.util.concurrent.Executor接口。 实际上&#xff0c;它存在的主要原因是为了在使用线程池的时候&#xff0c;将对Java 5的依赖抽象出来。 这个接口只有一个方法execute(Runnable task)&#xff0c;它根据线程池的语义和…

小程序居然可以用WXS模拟实现过滤器!

小程序目前官方还没有出过滤器&#xff0c;特别不方便&#xff0c;但是可以用wxs来模拟过滤器&#xff0c;话不多说&#xff0c;直接上代码。当然&#xff0c;不熟悉wxs的可以先看一下 官方文档 1.新建一个filter.wxs的文件我个人建议是一个过滤器写一个wxs&#xff0c;避免引用…

ADF:使用HTTP POST方法进行URL任务流调用

众所周知&#xff0c;可以通过某些URL直接从浏览器或某些外部应用程序调用有限任务流。 如果任务流的属性“ URL invoke”设置为“ url-invoke-allowed”&#xff0c;则启用此功能&#xff0c;该功能通常在集成项目中使用。 通常&#xff0c;客户端&#xff08;或调用者&#x…

java 项目做多级缓存_【开源项目系列】如何基于 Spring Cache 实现多级缓存(同时整合本地缓存 Ehcache 和分布式缓存 Redis)...

一、缓存当系统的并发量上来了&#xff0c;如果我们频繁地去访问数据库&#xff0c;那么会使数据库的压力不断增大&#xff0c;在高峰时甚至可以出现数据库崩溃的现象。所以一般我们会使用缓存来解决这个数据库并发访问问题&#xff0c;用户访问进来&#xff0c;会先从缓存里查…

Spring MVC:带有CNVR卷的REST应用程序。 3

这是带有CNVR的Spring MVC REST教程的最后一部分。 在这里&#xff0c;我将演示所有这些东西如何工作&#xff0c;这是我在前两部分中开发的。 对于每种类型的CRUD操作&#xff0c;这将分为四个部分&#xff1a;CREATE&#xff0c;READ&#xff0c;UPDATE&#xff0c;DELETE。 …

java 中io的删除文件_总结删除文件或文件夹的7种方法-JAVA IO基础总结第4篇

本文是Java IO总结系列篇的第4篇&#xff0c;前篇的访问地址如下&#xff1a;如果您阅读完成&#xff0c;觉得此文对您有帮助&#xff0c;请给我点个赞&#xff0c;您的支持是我不竭的创作动力。为了方便大家理解&#xff0c;我特意制作了本文对应的视频&#xff1a;总结删除文…

实现小程序canvas拖拽功能

组件地址 https://github.com/jasondu/wx-comp-canvas-drag 实现效果 如何实现 使用canvas使用movable-view标签 由于movable-view无法实现旋转&#xff0c;所以选择使用canvas 需要解决的问题 如何将多个元素渲染到canvas上如何知道手指在元素上、如果多个元素重叠如何知…

H5页面滚动阻尼效果实现

功能描述 要求 页面分为AB两个区域 当手机可视区的底部接触到 “阻尼带” 的时候&#xff0c;有个上拉弹性过程 当上拉到一定阈值程度就直接把B区顶部弹到手机可视区的顶部&#xff0c;让可视区从B区开始显示当上拉程度未到阈值&#xff0c;就回弹复原 当手机可视区从B区向上…

web 前端 html

1&#xff0c;什么是web 在网络中&#xff0c;大量的数据需要有一个载体&#xff0c;而很多人都能够访问这个载体&#xff0c;利用浏览器的这个窗口链接一个有一个载体&#xff0c;这个载体就是网站也就是web的前身。  1&#xff0c;web标准&#xff1a;结构标准&#xff0c;表…

再谈前后端分离

前段时间我针对手头上的项目前端配置进行了反思以及总结并且写了两篇文章: webpack传统后端渲染的项目前端配置, webpack配置之前后端不分离, 很显然这些配置能满足一时的需求, 但是也有不足. 今天继续总结, 这里应该不涉及到具体后端语言, 只对前端配置进行描述. 毕竟配置工程…

Python - day1 借鉴洪卫

一、了解开发语言 1、高级语言&#xff1a;Python&#xff0c;Java&#xff0c;C&#xff0c;C#&#xff0c;PHP&#xff0c;JS&#xff0c;Go&#xff0c;Ruby&#xff0c;SQL&#xff0c;Swift&#xff0c;Perl&#xff0c;Objective-C&#xff0c;R等等&#xff1b; 2、低级…

返回一个二维整数数组最大子数组的和

要求&#xff1a; 1&#xff0c;输入一个二维整形数组&#xff0c;数组里有正数也有负数。 2&#xff0c;二维数组中连续的一个子矩阵组成一个子数组&#xff0c;每个子数组都有一个和, 3&#xff0c;求所有子数组的和的最大值。 设计思路&#xff1a; 参照一维整数数组求解最大…

基于React的表单开发的分析(上)

本文主要讲解后台系统与表单相关的页面开发&#xff0c;并分析如何才能更好地、高效地开发。 技术栈 ReactAntd 背景 Antd 以下我都将Ant Design 简称为 Antd Ant Design是个服务于企业级产品的UI框架&#xff0c;主要可以用于中后台系统,它有基于React、Vue和Angular的实现…

50个Servlet面试问答

Servlet是Java EE的一个非常重要的主题&#xff0c;所有Web应用程序框架&#xff08;例如Spring和Struts&#xff09;都建立在它之上。 这使servlet成为Java访谈中的热门话题。 在这里&#xff0c;我提供了50个servlet面试问题的列表&#xff0c;并提供了答案&#xff0c;以帮…

深入浅出的webpack4构建工具--webpack4+react构建环境(二十)

下面我们来配置下webpack4react的开发环境&#xff0c;之前都是针对webpack4vue的。下面我们也是在之前项目结构的基础之上进行配置下。 首先看下如下是我为 webpack4react 基本的项目结构如下&#xff1a; ### 目录结构如下&#xff1a; demo1 …

Webpack 4进阶--从前的日色变得慢 ,一下午只够打一次包

从前的日色变得慢&#xff0c;车&#xff0c;马&#xff0c;邮件都慢&#xff0c;一生只够爱一个人 -- 《从前慢》 近期在团队项目里把Webpack升级到4.4.1&#xff0c;过程中发现现存的升级文档十分有限&#xff0c;踩了不少坑&#xff0c;好在升级之后提升还算显著&#xff0c…

编码Java时的10个微妙的最佳实践

这是10个最佳实践的列表&#xff0c;这些最佳实践比您的平均Josh Bloch有效Java规则要微妙得多。 尽管Josh Bloch的列表很容易学习&#xff0c;并且涉及日常情况&#xff0c;但此处的列表包含了涉及API / SPI设计的较不常见的情况&#xff0c;但可能会产生很大的影响。 我在编…

Vue 实现微信 jssdk 扫码, 上传图片

流程 1: 配置微信公众号JS域名 2:前端发送URL后台获取JSSDK配置, 后台Service代码如下, 修改2处位置: WeixinUtil.APPID > 当前公众号APPID WeixinUtil.getAccessToken() > 当前公众号access_token public interface IWxJssdkService {Map<String, Object> getJssd…