首页
统计
留言板
友接
推荐
免费图床
服务监控
Search
1
immich开源相册部署教程
817 阅读
2
GraalVM将Java打包原生Native应用
327 阅读
3
将旧手机改造成Linux服务器
278 阅读
4
Java函数式编程
185 阅读
5
FRP内网穿透教程
168 阅读
编程语言
Java
Python
Go
单片机
Arduino
ESP8266
ESP32
STM32
51单片机
树莓派
运维
Docker容器
随身小记
登录
Search
标签搜索
Spring
SpringMVC
Java
docker
DSM
群晖
iptables
ssh
spring
mybaits
redis
SpringBoot
消息队列
科长
累计撰写
36
篇文章
累计收到
5
条评论
首页
栏目
编程语言
Java
Python
Go
单片机
Arduino
ESP8266
ESP32
STM32
51单片机
树莓派
运维
Docker容器
随身小记
页面
统计
留言板
友接
推荐
免费图床
服务监控
搜索到
11
篇与
Java
的结果
2024-11-18
SpringBoot 集成 Solr 实现高效全文检索服务
简介Solr 是一个基于 Apache Lucene 构建的开源搜索平台。它提供了强大的搜索功能、高效的索引机制和丰富的配置选项,使得开发者能够轻松构建高性能的搜索应用。Solr 具有易于使用的 Web 管理界面,方便进行配置和监控。它支持多种数据格式的索引和搜索,能够处理大量的数据,并提供了诸如分页、排序、过滤、高亮显示搜索结果等功能。有了 MySQL 还有必要用 Solr 吗即使已经使用了 MySQL 这样的关系型数据库,在某些情况下使用 Solr 仍然是有必要的。MySQL 擅长处理结构化数据的存储和事务操作,但在搜索功能方面存在一些局限性。例如,对于复杂的全文搜索、模糊搜索、相关性排序等需求,MySQL 可能无法提供高效和灵活的解决方案。而 Solr 专门为搜索进行了优化,能够快速处理大规模的文本数据搜索,并提供更精确的搜索结果排序和相关性计算。举例来说,如果您的应用需要快速搜索大量的文章内容、产品描述等文本信息,并且对搜索的响应速度和准确性要求较高,那么单独依靠 MySQL 可能无法满足需求,此时结合 Solr 可以显著提升搜索体验。另外,如果需要实现实时搜索、动态索引更新等功能,Solr 也更具优势。安装Solr下载运行前往solr的官方下载地址:https://solr.apache.org/downloads.htmlSolr 9.x 版本最低运行要求是 Java 11,我一直使用的是 Java 8 所以这里我将使用 Solr 8.x 作为本次的教程版本。下载后将其解压会得到如下的目录结构:打开终端,进入bin目录中启动Solr服务:Windows用户则只需要执行下面的命令:solr start安装中文分词器中文具有独特的语言结构和语义表达,不像英文等语言,单词之间通常有明显的空格分隔。如果直接使用 Solr 默认的分词器处理中文文本,可能会将中文拆分成单个的汉字,而不是按照中文的词语进行切分。前往Maven仓库下载分词依赖:https://mvnrepository.com/artifact/com.github.magese/ik-analyzer/8.5.0将下载下来的 ik-analyzer-8.5.0.jar 放入到 solr-8.11.3/server/solr-webapp/webapp/WEB-INF/lib 中我们在终端使用命令创建一个 core 来测试一下分词器: ./solr create -c ik_core 然后在 solr-8.11.3/server/solr 下可以看到一个名为 ik_core 的目录:在 conf 目录下编辑 managed-schema 文件并写入以下内容:<!-- IKAnalyzer--> <fieldType name="text_ik" class="solr.TextField" autoGeneratePhraseQueries="false"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer" type="index"> </analyzer> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer" type="query"> </analyzer> </fieldType>重启Solr服务:测试分词器在 Solr Admin 中,也就是solr的web界面,选择我们创建的 ik_core 在 Analysis 中测试分词效果(Analyse Fieldname / FieldType 选择为 text_ik):集成到SpringBoot创建SpringBoot项目SpringBoot项目的创建可以借助IDE完成,这里就不再叙述了。添加maven依赖在项目的 pom.xml 中添加新的依赖:<dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-solrj</artifactId> <version>8.11.3</version> </dependency>创建配置在application.yml中添加solr的配置信息:solr: host: http://127.0.0.1:8983/solr创建配置类:import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SolrConfig { @Value("${solr.host}") private String solrHost; @Bean public SolrClient solrClient() { return new HttpSolrClient.Builder(solrHost).build(); } }创建文档索引在查询数据之前,我们需要在solr中导入我们的数据,并建立索引。第一种方式来添加文档比较简单:@Resource private SolrClient solrClient; public void indexQuestion() throws Exception{ // 创建一个文档对象 SolrInputDocument inputDocument = new SolrInputDocument(); // 添加字段 inputDocument.addField("id", "1"); inputDocument.addField("name", "名称1"); inputDocument.addField("content", "内容1"); inputDocument.addField("category", "类别1"); // 将文档写入索引库中 solrServer.add("ik_core", inputDocument); // 提交 solrServer.commit("ik_core"); }第二种方式则是实用Java Bean的方式,其字段属性使用Solr提供的的 @Field 注解标柱:@Data public class Document { @Field private String id; @Field private String name; @Field private String content; @Field private String category; }然后实例化Bean,并将其添加到我们创建的 ik_core 中进行索引:@Resource private SolrClient solrClient; public boolean indexQuestion() throws SolrServerException, IOException { // 实例化并添加 Document 对象 Document doc1 = new Document(); doc1.setId("1"); doc1.setName("国内新能源汽车销量持续攀升"); doc1.setContent("今年以来,国内新能源汽车市场表现强劲,销量不断增长。各大厂商纷纷推出新款车型,技术创新不断。"); doc1.setCategory("汽车"); solrClient.addBean("ik_core", doc1); Document doc2 = new Document(); doc2.setId("2"); doc2.setName("国内电商行业发展新趋势"); doc2.setContent("随着数字化转型的加速,国内电商行业呈现出直播带货、社交电商等新趋势,消费者购物方式发生显著变化。"); doc2.setCategory("电商"); solrClient.addBean("ik_core", doc2); Document doc3 = new Document(); doc3.setId("3"); doc3.setName("国内5G网络建设加速推进"); doc3.setContent("国内5G网络覆盖范围持续扩大,为智能制造、智慧城市等领域的发展提供了有力支撑。"); doc3.setCategory("通信"); solrClient.addBean("ik_core", doc3); Document doc4 = new Document(); doc4.setId("4"); doc4.setName("国内旅游市场逐渐复苏"); doc4.setContent("在疫情防控形势好转的背景下,国内旅游市场迎来复苏,各地旅游景点游客数量逐步增加。"); doc4.setCategory("旅游"); solrClient.addBean("ik_core", doc4); Document doc5 = new Document(); doc5.setId("5"); doc5.setName("国内医疗改革取得新进展"); doc5.setContent("近年来,国内医疗改革不断深化,医保政策优化,医疗服务质量得到提升。"); doc5.setCategory("医疗"); solrClient.addBean("ik_core", doc5); // 提交 UpdateResponse updateResponse = solrClient.commit("ik_core"); return updateResponse != null && updateResponse.getStatus() == 0; }当有了这些数据后,我们即可对这些数据进行检索操作,第一次我们写简单点进行查询:public void query() throws SolrServerException, IOException { // 创建查询语句 SolrQuery query = new SolrQuery(); // 设置查询条件 query.set("q", "id:1"); // 执行查询 QueryResponse queryResponse = solrClient.query("ik_core", query); // 取文档列表 SolrDocumentList documentList = queryResponse.getResults(); for (SolrDocument solrDocument : documentList) { System.out.println("id:"+solrDocument.get("id")+" "); System.out.println("名称:"+solrDocument.get("name")+" "); System.out.println("内容:"+solrDocument.get("content")+" "); System.out.println("类别:"+solrDocument.get("category")+" "); } // 也可以反序列化为Java Bean List<Document> documents = queryResponse.getBeans(Document.class); for (Document document : documents) { System.out.println("id:" + document.getId()); System.out.println("名称:" + document.getName()); System.out.println("内容:" + document.getContent()); System.out.println("类别:" + document.getCategory()); } }接下来可以构造条件丰富的查询: public void query() throws Exception { // 创建查询语句 SolrQuery query = new SolrQuery(); // 设置查询关键字 query.set("q", "国内"); // 按照id降序排列 query.setSort("id", SolrQuery.ORDER.desc); // 分页条件 query.setStart(0); query.setRows(2); // 在指定的字段中进行查询 query.set("df", "name"); // 设置高亮 query.setHighlight(true); // 设置高亮的字段 query.addHighlightField("name,content"); // 设置高亮的样式 query.setHighlightSimplePre("<font color='red'>"); query.setHighlightSimplePost("</font>"); // 执行查询 QueryResponse queryResponse = solrClient.query("ik_core", query); // 返回高亮显示结果 Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting(); System.out.println(highlighting); // 获取文档列表 SolrDocumentList documentList = queryResponse.getResults(); System.out.println("总记录数:" + documentList.getNumFound()); for (SolrDocument solrDocument : documentList) { System.out.println("id:" + solrDocument.get("id") + " "); System.out.println("名称:" + solrDocument.get("name") + " "); System.out.println("内容:" + solrDocument.get("content") + " "); System.out.println("类别:" + solrDocument.get("category") + " "); } }删除文档则可以使用id字段进行删除:public void deleteQuestion() throws SolrServerException, IOException { solrClient.deleteById("ik_core", "1"); // 提交 solrClient.commit("ik_core"); }总体的来说 Solr 是一款开源的高性能搜索平台,具有强大搜索功能、可扩展性、丰富特性、灵活配置且易于集成,能满足各种复杂搜索和数据管理需求。
2024年11月18日
19 阅读
0 评论
0 点赞
2023-07-10
Java函数式编程
在程序开发中使用函数式编程,可以减少冗杂的代码,加快开发速度等。接下来,我将给大家讲讲在 Java 8 中的三种函数式编程的方法,lambda 表达式、:: 符号和 Optional 类,下面是详细内容。1、函数式编程函数式编程(Functional Programming)属于编程范式(Programming Paradigm)中的用语,此外还有命令式编程(Imperative Programing)等,有兴趣的同学可以自行了解,我们这里大概解释一下函数式编程,在函数式编程中,输入一旦确定了,输出都确定了,函数调用的结果只依赖于传入的输入变量和内部逻辑,不依赖于外部,这样的写出的函数没有副作用。举个例子:public class Test { private int a = 1; public int add(int b) { return a + b; } public int pow(int c) { return c * c; } public static void main(String[] args) { Test t = new Test(); t.add(1); t.pow(2); } }上面代码中add(int b)这个方法就不符合函数式编程,这个函数调用后的结果不确定,它的结果不仅取决于b还取决于字段a。而pow(int c)这函数就是符合函数式编程的典范,只要调用它,输入的值c确定了返回值就肯定确定了。 在函数式编程中,函数也是一等公民,可以被当做参数传递,可以被赋值,被引用,可以把它当做一种数据类型来对待,如果你会使用javascript之类的语言就可以有更深的体会。如果要深入了解这种编程范式可以自行网上搜素资料了解。2、lambda表达式lambda表达式是jdk8中的新特性,上面讲函数式编程就是引入这个,oracle在jdk8中引入了lambda,从此Java中开始对函数式编程的部分支持。 Java中lambda表达式的语法结构:(params) -> expression由三部分构成,第一部分是括号以及括号内部的形式参数,第二部分是->箭头符号,第三部分是expression方法体,方法体可以是代码块也可以是执行表达式。// lambda 表达式 完整状态 有入参 有返回 有代码块 (int a, int b) -> { int c = a + b; return c; } // 当代码不需要返回值 则可省去 return (int a, int b) -> { int c = a + b; } // 当代码只有一句话的时候可以省去 大括号 (int a, int b) -> a + b; // 同样可以省略形参类型 (a, b) -> a + b; // 当只有一个参数时, 可以省去形参的小括号 a -> a * a;接下来使用lambda表达式来定义和实现一个函数式接口:@FunctionalInterface public interface ITest { int add(int a, int b); }内部匿名类实现方式:public static void main(String[] args) { ITest iTest = new ITest() { @Override public int add(int a, int b) { return a + b; } }; iTest.add(1, 1); }Lambda实现方式: public static void main(String[] args) { ITest t = (a, b) -> a + b; t.add(1, 1); }使用lambda表达式会使代码更加的优雅3、使用双冒号::符号对上面的Lambda实现方式进行进步一步的优化:public static void main(String[] args) { ITest t = Integer::sum; t.add(1, 1); }双冒号的使用方式:类名::静态方法名或者 类的实例::实例方法4、Optional类Optional也是jdk8中的一个新的类的,它给予我们更加优雅的方式来处理Java语言中的NPE异常。可以从一定程度上代替if判断, 介绍相关接口:empty 创建一个空的Optional对象of 和ofNullableof创建一个Optional对象, 如果传入的参数为空则跑出NPE异常.ofNullable和上面一样, 但是当传入参数为空的时候会调用empty方法创建一个空Optional对象.Optional<String> of = Optional.of("waxxd"); // 传入空参数会抛出NullPointerException异常 Optional<String> ofNull = Optional.of(null); // 以下两句都正常执行 Optional<String> ofNullable = Optional.ofNullable("waxxd"); // 参数为空的时候相当调用Optional.empty() Optional<String> ofNullableNull = Optional.ofNullable(null); get/orElse/orElseGet/orElseThrow// get 获取Option包裹的值如果值为null则抛出NoSuchElementException异常 String aa = Optional.of("aa").get(); // orElse 获取值如果值为空则返回orElse设置的默认值 String aa1 = Optional.of("aa").orElse("bb"); // orElseGet 获取值如果值为空则内部可以是一个实现Supplier接口的匿名内部类调用提供返回结果 String aa2 = Optional.of("aa").orElseGet( () -> "aaa".toUpperCase()); // orElseThrow获取值如果不存在则抛出后面的异常 Optional.empty().orElseThrow(IllegalArgumentException::new); // 实际的应用, 也就是上文所说的如何优化if // 比如你有个接口, 用户传入参数Integer type, 用户也可以选择不传, 不传我们为它设置默认值1 public void f(Integer type){ if(type = null) { type = 1; } Optional.ofNullable(type).orElse(1); }
2023年07月10日
185 阅读
0 评论
0 点赞
GraalVM将Java打包原生Native应用
2023年07月10日
327 阅读
0 评论
0 点赞
2023-07-10
GraalVM 是一种高性能 JDK,旨在加速 Java 应用程序性能,同时消耗更少的资源。 它提供了 Graal 编译器,它可以用作即时编译器,在 HotSpot JVM 上运行 Java 应用程序或提前将它们编译为本机可执行文件。除了Java,它还为JavaScript,Ruby,Python和其他几种具有多语言功能的流行语言提供了运行时。Graalvm下载地址 Releases · graalvm/graalvm-ce-builds (github.com))安装Graalvm环境由于本人电脑是macos则此处演示macos的安装和使用方法。在其他系统中安装方式大同小异,都是相当于添加一个新的jdk环境首先去官网下载对应自己平台和版本的包。我是MacOS M1,使用Java11环境,所所以此处我选择的是 macOS(aarch64)的包。下载完成后进行解压,移动到指定位置sudo mv graalvm-ce-java11-22.3.1 /Library/Java/JavaVirtualMachines/然后删除隔离属性 sudo xattr -r -d com.apple.quarantine /Library/Java/JavaVirtualMachines/graalvm-ce-java11-22.3.1添加环境变量添加完环境变量后使其生效如果输入java -version 输出 OpenJDK Runtime Environment GraalVM CE 22.3.1 (build 11.0.18+10-jvmci-22.3-b13)则表示环境已经添加成功了,整个步骤就是在添加一个新的Java环境IDEA集成Graalvm在IDEA新增项目,并在新增界面添加新的JDKAdd JDK,新建项目并编写一个main方法在mavenpom.xml中增加graalvm的打包插件<build> <plugins> <plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> <configuration> <!-- imageName用于设置生成的二进制文件名称 --> <imageName>${project.artifactId}</imageName> <!-- mainClass用于指定main方法类路径 --> <mainClass>com.bystart.Main</mainClass> <buildArgs> --no-fallback </buildArgs> </configuration> </plugin> </plugins> </build>打包测试输入打包命令进行打包mvn -Pnative native:compile或者使用IDEA的maven工具打包运行测试
2023-07-07
SpringBoot集成Redis发布订阅模式
Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。Redis 客户端可以订阅任意数量的频道。新建SpringBoot项目POM添加依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>添加配置在application.yml中配置redis连接信息:server: port: 8888 spring: datasource: redis: host: 127.0.0.1 port: 6379 cache: type: redis创建redis配置类package com.bystart.redis.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; public class RedisConfig { @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(mapper); template.setValueSerializer(jackson2JsonRedisSerializer); //使用StringRedisSerializer来序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.afterPropertiesSet(); return template; } }监听主题处理监听到的消息package com.bystart.redis.listener; import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.Resource; @Component public class RedisMessageListener implements MessageListener { @Resource private RedisTemplate redisTemplate; @Override public void onMessage(Message message, byte[] pattern) { // 解析消息体 byte[] messageBody = message.getBody(); // 使用值序列化器转换 Object msg = redisTemplate.getValueSerializer().deserialize(messageBody); // 获取监听的主题 byte[] channelByte = message.getChannel(); // 使用字符串序列化器转换 Object channel = redisTemplate.getStringSerializer().deserialize(channelByte); // 主题名称转换 String patternStr = new String(pattern); System.out.println(patternStr); System.out.println("---主题---: " + channel); System.out.println("---消息内容---: " + msg); } }配置监听主题和消费者package com.bystart.redis.config; import com.bystart.redis.listener.RedisMessageListener; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; @Configuration public class RedisSubConfig { @Bean public RedisMessageListenerContainer container(RedisConnectionFactory factory, RedisMessageListener listener){ RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(factory); // 监听指定主题,将收到的消息移交给 RedisMessageListener 处理 container.addMessageListener(listener, new ChannelTopic("login.notice")); return container; } }推送测试新增一个controller:package com.bystart.redis.controller; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController public class TestController { @Resource private RedisTemplate redisTemplate; @GetMapping public String test(@RequestParam String message) { redisTemplate.convertAndSend("login.notice", message); return "ok: " + message; } }访问http://127.0.0.1:8888?message=hello返回login.notice ---频道---: login.notice ---消息内容---: hello
2023年07月07日
101 阅读
0 评论
0 点赞
IDEA整合SSM框架
2023年07月06日
109 阅读
0 评论
0 点赞
2023-07-06
创建项目打开IDEA-File-Project项目大致目录项目目录类型修改pom.xml添加maven依赖 <properties> <!-- 设置项目编码编码 --> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <!-- spring版本号 --> <spring.version>4.3.5.RELEASE</spring.version> <!-- mybatis版本号 --> <mybatis.version>3.4.1</mybatis.version> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.apache.taglibs</groupId> <artifactId>taglibs-standard-impl</artifactId> <version>1.2.5</version> </dependency> <!-- 实现slf4j接口并整合 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <!-- JSON --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.8.7</version> </dependency> <!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.25</version> <scope>runtime</scope> </dependency> <!-- 数据源 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> <!-- MyBatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <!-- mybatis/spring整合包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>spring-ssm</finalName> </build>配置DispatcherServlet有关DispatcherServlet前端控制器的文章可以查看SpringMVC之DispatcherServlet前置控制器编辑web.xml<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>ssm</display-name> <!--添加防止乱码的过滤器--> <filter> <!--过滤器名称--> <filter-name>SetCharacterEncoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!--设置CharacterEncodingFilter属性--> <!--encoding属性--> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <!--forceEncoding属性--> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <!--映射过滤器--> <filter-mapping> <!--使用哪个过滤器--> <filter-name>SetCharacterEncoding</filter-name> <!--配置全局路由需要使用这个过滤器--> <url-pattern>/*</url-pattern> </filter-mapping> <!--配置 DispatcherServlet 调度器--> <servlet> <servlet-name>SpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--初始化 DispatcherServlet--> <!-- SpringMVC通过web.xml文件中servlet标签下的DispatcherServlet类完成自身的初始化--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-*.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!--映射所有请求到 DispatcherServlet 调度器--> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 默认首页 --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> 在这里提一嘴,很多同学不太明白拦截器和过滤器的区别,现在跟大家解释一下两者的区别:拦截器是基于Java的反射机制的,而过滤器则是基于函数的回调拦截器是实现HandleInterceptor,过滤器则是实现Filter接口拦截器不依赖于Servlet容器,过滤器依赖于Servlet容器拦截器使用来验证请求,能截断请求。过滤器用来设置request,response参数、属性,侧重对数据的过滤过滤器在拦截器之前执行过滤器是tomcat服务器创建的对象,拦截器是springmvc容器创建的对象过滤器可以处理jsp、js、html等;拦截器是侧重拦截Controller的对象,如果你的请求不能被DispatcherServlet接收,这个请求不会执行拦截器的内容拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑配置SpringMVC在classpath目录下也就是resources目录下新增spring-mvc.xml配置文件,写入:<?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.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.bystart.ssm.controller"/> <!--开启springmvc模式--> <mvc:annotation-driven/> <!--静态资源默认servlet配置--> <mvc:default-servlet-handler/> <!--配置jsp 显示viewResolver --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> </beans>集成MySQL、MyBatis同样是是在resources目录下,首先先创建mysql的连接配置文件jdbc.propertiesjdbc.driver=com.mysql.jdbc.Driver #数据库地址 jdbc.url=jdbc:mysql://127.0.0.1:3306/ssmdb?useUnicode=true&characterEncoding=utf8&useSSL=false #用户名 jdbc.username=root #密码 jdbc.password=123456 #最大连接数 c3p0.maxPoolSize=30 #最小连接数 c3p0.minPoolSize=10 #关闭连接后不自动commit c3p0.autoCommitOnClose=false #获取连接超时时间 c3p0.checkoutTimeout=10000 #当获取连接失败重试次数 c3p0.acquireRetryAttempts=2继续添加spring-mybatis.xml:<?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:tx="http://www.springframework.org/schema/tx" 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/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--配置数据库相关信息--> <!--读取数据库的连接配置信息--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--构建数据库连接池--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="maxPoolSize" value="${c3p0.maxPoolSize}"/> <property name="minPoolSize" value="${c3p0.minPoolSize}"/> <property name="autoCommitOnClose" value="${c3p0.autoCommitOnClose}"/> <property name="checkoutTimeout" value="${c3p0.checkoutTimeout}"/> <property name="acquireRetryAttempts" value="${c3p0.acquireRetryAttempts}"/> </bean> <!--配置SqlSessionFactory对象--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--注入数据连接池--> <property name="dataSource" ref="dataSource"/> <!--扫描entity包 使用别名--> <property name="typeAliasesPackage" value="com.bystart.ssm.model"/> <!--扫描mapper文件--> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <!--配置事务管理--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据连接池--> <property name="dataSource" ref="dataSource"/> </bean> <!--配置使用注解声明式事务--> <tx:annotation-driven transaction-manager="transactionManager"/> <!--扫描Dao接口包 自动注入到spring容器--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--注入sqlSessionFactory--> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!--dao接口包路径--> <property name="basePackage" value="com.bystart.ssm.dao"/> </bean> <!--扫描dao包下所有使用注解的类型--> <context:component-scan base-package="com.bystart.ssm.dao"/> <!--扫描service包下所有使用注解的类型--> <context:component-scan base-package="com.bystart.ssm.service"/> </beans> 添加日志输出新增logback-spring.xml同样是在resources目录下<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <root level="debug"> <appender-ref ref="STDOUT"/> </root> </configuration>实战从数据库查询数据数据库表结构:CREATE TABLE `sys_user` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', `username` varchar(32) NOT NULL COMMENT '用户名', `password` varchar(32) NOT NULL COMMENT '密码', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;插入数据:INSERT INTO `sys_user` (`id`, `username`, `password`) VALUES (1, 'sysadmin', '123456');编写数据表对应的JavaBean在包路径com.bystart.ssm.model下创建数据库表对应的Java类实体package com.bystart.ssm.model; public class SysUserEntity { /** * 自增id */ private Long id; /** * 用户名 */ private String username; /** * 密码 */ private String password; public SysUserEntity() { } public SysUserEntity(Long id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "SysUserEntity{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }编写数据交互层DAO在包com.bystart.ssm.dao路径下添加接口package com.bystart.ssm.dao; import com.bystart.ssm.model.SysUserEntity; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; import java.util.List; public interface SysUserDao{ /** * 查询所有的用户 * */ List<SysUserEntity> getUserList(); /** * 根据用户名查询指定用户 * */ SysUserEntity getUserByUsername(@Param("username") String username); }编写SysUserDao.xml在resources-mapper目录下新增SysUserDao.xml<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.bystart.ssm.dao.SysUserDao"> <select id="getUserList" resultType="com.bystart.ssm.model.SysUserEntity"> select * from sys_user </select> <select id="getUserByUsername" resultType="com.bystart.ssm.model.SysUserEntity"> select * from sys_user where username = #{username} </select> </mapper>编写业务层接口在com.bystart.ssm.service新增SysUserService接口,并提供两个方法package com.bystart.ssm.service; import com.bystart.ssm.model.SysUserEntity; import java.util.List; public interface SysUserService { /** * 查询所有的用户 * */ List<SysUserEntity> getUserList(); /** * 根据用户名查询用户的信息 * @param username 用户名查询条件 * */ SysUserEntity getUserByUsername(String username); }添加service的实现类,在com.bystart.ssm.service.impl包下新增SysUserServiceImpl实现类package com.bystart.ssm.service.impl; import com.bystart.ssm.dao.SysUserDao; import com.bystart.ssm.model.SysUserEntity; import com.bystart.ssm.service.SysUserService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; @Service public class SysUserServiceImpl implements SysUserService { @Resource private SysUserDao dao; @Override public List<SysUserEntity> getUserList() { return dao.getUserList(); } @Override public SysUserEntity getUserByUsername(String username) { return dao.getUserByUsername(username); } }编写controllercom.bystart.ssm.controller包下新增SysUserControllerpackage com.bystart.ssm.controller; import com.bystart.ssm.model.SysUserEntity; import com.bystart.ssm.service.SysUserService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import javax.annotation.Resource; import java.util.List; @Controller public class SysUserController { @Resource private SysUserService service; /** * 查询用户列表并返回到JSP进行数据渲染 */ @RequestMapping("/getUserList") public String getUserList(Model model) { List<SysUserEntity> userList = service.getUserList(); model.addAttribute("userList", userList); // 返回到 webapp目录下的 WEB-INF > views > userList.jsp return "userList"; } /** * 根据用户名查询指定用户 * 将查询到的数据以json形式返回到页面 * * @param username 用户名 */ @RequestMapping("/getUserByUsername") @ResponseBody public SysUserEntity getUserByUsername(@RequestParam String username) { SysUserEntity user = service.getUserByUsername(username); return user; } }编写JSP页面在webapp -> WEB-INF -> views目录下新增userList.jsp:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%-- Created by IntelliJ IDEA. User: bystart Date: 2023/7/6 Time: 15:32 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html> <head> <title>Title</title> </head> <body> <table border=1> <thead> <tr> <th>序号</th> <th>用户名</th> <th>密码</th> </tr> </thead> <tbody> <c:forEach items="${userList}" var="user"> <tr> <th>${user.id}</th> <th>${user.username}</th> <th>${user.password}</th> </tr> </c:forEach> </tbody> </table> </body> </html>配置tomcat配置好tomcat后即可运行起来测试发起请求获得数据我们编写的SysUserController中有两个接口,一个会返回页面,一个会返回json数据我们在浏览器中请求http://localhost:8080/ssm/此处的地址可以在这里查看在浏览器访问http://localhost:8080/ssm/getUserList再去访问http://localhost:8080/ssm/getUserByUsername?username=sysadmin如果能跟我一样正常显示,说明ssm框架搭建完成,并且可以跟数据库进行交互
2023-07-04
SpringMVC @Controller注解定义一个控制器
@Controller注解当他标注在类的上方就表明了一个类作为控制器的角色而存在。Spring不要求你去继承任何控制器基类,也不需要去实现Servlet的那套API,如果你想去实现也是可以的@Controller注解可以认为是被标注类的原型(stereotype),表明这个类所承担的角色。分派器(dispatcherServlet)会扫描所有注解了@Controller的类,并检测其中被@RequestMapping注解配置的方法当然,你也可以不使用@Controller注解而显式地去定义被注解的bean,这点通过标准的Spring bean的定义方式,在dispather的上下文属性下配置即可做到。但是@Controller原型是可以被框架自动检测的,Spring支持classpath路径下组件类的自动检测,以及对已定义bean的自动注册@Controller public class DemoController { ..... }如果想要开启自动对控制器注解的自动检测,需要在spring-context.xml中开启注解扫描<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" 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"> <!-- 扫描并加载此包下的所有被@Controller注解的类 <--> <context:component-scan base-package="org.springframework.samples.controller"/> <!-- ... --> </beans>
2023年07月04日
118 阅读
0 评论
0 点赞
2023-07-04
SpringMVC了解WebApplicationContext中特殊的bean类型
Spring的DispatcherServlet使用了特殊的bean来处理请求、渲染视图等,这些特定的bean是Spring MVC框架的一部分。如果你想指定使用哪个特定的bean,你可以在web应用上下文WebApplicationContext中简单地配置它们。当然这只是可选的,Spring MVC维护了一个默认的bean列表,如果你没有进行特别的配置,框架将会使用默认的bean。下一小节会介绍更多的细节,这里,我们将先快速地看一下,DispatcherServlet都依赖于哪些特殊的bean来进行它的初始化。bean的类型作用HandlerMapping处理器映射。它会根据某些规则将进入容器的请求映射到具体的处理器以及一系列前处理器和后处理器(即处理器拦截器)上。具体的规则视HandlerMapping类的实现不同而有所不同。其最常用的一个实现支持你在控制器上添加注解,配置请求路径。当然,也存在其他的实现。HandlerAdapter处理器适配器。拿到请求所对应的处理器后,适配器将负责去调用该处理器,这使得DispatcherServlet无需关心具体的调用细节。比方说,要调用的是一个基于注解配置的控制器,那么调用前还需要从许多注解中解析出一些相应的信息。因此,HandlerAdapter的主要任务就是对DispatcherServlet屏蔽这些具体的细节。HandlerExceptionResolver处理器异常解析器。它负责将捕获的异常映射到不同的视图上去,此外还支持更复杂的异常处理代码。ViewResolver视图解析器。它负责将一个代表逻辑视图名的字符串(String)映射到实际的视图类型View上。LocaleResolver& LocaleContextResolver地区解析器 和 地区上下文解析器。它们负责解析客户端所在的地区信息甚至时区信息,为国际化的视图定制提供了支持。ThemeResolver主题解析器。它负责解析你web应用中可用的主题,比如,提供一些个性化定制的布局等。MultipartResolver解析multi-part的传输请求,比如支持通过HTML表单进行的文件上传等。FlashMapManagerFlashMap管理器。它能够存储并取回两次请求之间的FlashMap对象。后者可用于在请求之间传递数据,通常是在请求重定向的情境下使用。
2023年07月04日
86 阅读
0 评论
0 点赞
2023-07-04
SpringMVC之DispatcherServlet前置控制器
简介DispatcherServlet是前置控制器,配置在web.xml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自己定义,把拦截下来的请求,依据相应的规则分发到目标Controller来处理,是配置spring MVC的第一步。DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处。运行流程主要职责DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下:1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;2、通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);3、通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);4、通过ViewResolver解析逻辑视图名到具体视图实现;5、本地化解析;6、渲染具体的视图等;7、如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。DispatcherServlet初始化的上下文加载的Bean是只对SpringMVC有效的Bean,如Controller、HandlerMapping、HandlerAdapter等等,该初始化上下文只加载Web相关组件。DispatcherServlet初始化主要做了如下两件事情:1、初始化SpringMVC使用的Web上下文,并且可能指定父容器为(ContextLoaderListener加载了根上下文);2、初始化DispatcherServlet使用的策略,如HandlerMapping、HandlerAdapter等。配置DispatcherServlet下面的例子演示了如何配置DispatcherServlet。<web-app> <servlet> <servlet-name>example</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param>//初始化参数 <param-name>contextConfigLoaction</param-name> <param-value>classpath:applicationcontext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup>//启动级别为1 </servlet> <servlet-mapping> <servlet-name>example</servlet-name> <url-pattern>*.form</url-pattern> </servlet-mapping> </web-app>在上面的例子里,所有以.form结尾的请求都会由名为example的DispatcherServlet处理,这只是配置Spring Web MVC的第一步
2023年07月04日
109 阅读
0 评论
0 点赞
2023-07-04
SpringMVC框架简介
Spring MVC基本信息Spring 框架提供了构建Web应用程序的全功能MVC模块。使用Spring可插入的MVC架构,可以选择的是使用内置的Spring Web框架还是Struts这样的Web框架。通过策略接口,Spring框架是高度可配置的,而且包含多种视图技术,例如JavaServer Pages(JSP)技术、Velocity、Tiles、iText和POI。Spring MVC框架并不知道使用的视图,所以不会强迫您只使用JSP技术。Spring MVC分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。Spring MVC 简介SpringMVC指的是Spring的模型-视图-控制器(MVC)框架,是围绕一个DispatcherServlet来设计的,这个Servlet会把请求分发给各个处理器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传。处理器是你的应用中注解了@Controller和@RequestMapping的类和方法,Spring为处理器方法提供了极其多样的灵活配置。Spring3.0以后提供了@Controller注解机制、@PathVariable注解以及一些其他的特性,你可以使用它们进行RESTful web站点和应用的开发。Spring MVC的优点容易和其它View框架无缝集成,采用IoC便于测试它是体格典型的教科书式的mvc架构,而不像struts等都是变种或者不是完全基于mvc的系统的框架,Spring适用于初学者或者想了解mvc的人它和tapestry一样是一个纯正的servlet系统,这也是它和tapestry相比 struts所没有的优势。而且框架本身有代码,而且看起来也不费劲比较简单可以理解Spring MVC运行原理客户端请求提交到DispatcherServlet由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的ControllerDispatcherServlet将请求提交到ControllerController调用业务逻辑处理后,返回ModelAndViewDispatcherServlet查询一个或多个ViewResouler视图解析器,找到ModelAndView指定的视图视图负责将结果回显到客户端
2023年07月04日
101 阅读
0 评论
0 点赞
2023-07-04
Spring框架功能模块及概念
Spring框架功能模块及概念Spring框架采用分层架构,功能要素被分成可20个模块,分为 Core Contatiner、Data Access/Integration、Web、AOP、Instrumentation、Messaging和Test1、核心容器Core ContainerSpring的核心容器是其他模块建立的基础,它主要由Beans模块、Core模块、Context模块、Context-support模块和SpEl模块组成。Beans模块提供了BeanFactory,BeanFactory是工程模式的实现,被Spring托管的对象被称作为BeanCore核心模块提供了Spring框架的基本组成部分,其包括IoC和DI功能Context上下文管理,建立在Core和Beans模块的基础之上,它是访问定义和配置任何对象的工具,ApplicationContext接口是上下文的焦点Context-support 提供了对第三方依赖嵌入Spring应用的集成支持SpEL模块:是Spring 3.0后新增的模块,它提供了Spring Expression Language支持,是运行时查询和操作对象图的强大的表达式语言2、数据访问数据访问/集成层包括JDBC、ORM、OXM、JMS和Transactions模块JDBC模块提供了一个JDBC的抽象层,大幅度地减少了在开发过程中对数据库操作的编码ORM模块对流行的对象关系映射API,包括JPA、JDO和Hibernate提供了集成层支持OXM模块提供了一个支持对象/ XML映射的抽象层实现,如JAXB、Castor、XMLBeans、JiBX和XStreamJMS 模块指 Java 消息传递服务,包含使用和产生信息的特性,自 4.1 版本后支持与Spring-message模块的集成3、WEB支持Spring的Web层包括WebSocket、Servlet、Web和Portlet模块WebSocket模块Spring 4.0以后新增的模块,它提供了WebSocket 和SockJS的实现,以及对STOMP的支持Servlet模块也称为Spring-webmvc模块,包含了Spring的模型—视图—控制器(MVC)和REST Web Services实现的Web应用程序Web模块提供了基本的Web开发集成特性,例如:多文件上传功能、使用Servlet监听器来初始化IoC容器以及Web应用上下文Portlet模块提供了在Portlet环境中使用MVC实现,类似Servlet模块的功能4、Spring AOP/IoCSpring AOP及IoC详细介绍和使用方法可见Java Spring框架
2023年07月04日
68 阅读
0 评论
0 点赞
1
2