首页
友链
关于
免责声明
Search
1
王者营地战绩数据王者荣耀查询网页源码
7,817 阅读
2
群晖Active Backup for Business套件备份Linux服务器教程
4,533 阅读
3
影视分享
4,445 阅读
4
(亲测)Jrebel激活破解方式2019-08-21
4,428 阅读
5
centos7 安装及卸载 jekenis
3,694 阅读
日常
文章
后端
前端
Linux
异常
Flutter
分享
群辉
登录
Search
标签搜索
docker
springboot
Spring Boot
java
linux
Shiro
Graphics2D
图片
游戏账号交易
Mybatis
Spring Cloud
centos
脚本
Web Station
群辉
王者营地
战绩查询
平台对接
Spring Cloud Alibaba
nacos
绿林寻猫
累计撰写
249
篇文章
累计收到
26
条评论
首页
栏目
日常
文章
后端
前端
Linux
异常
Flutter
分享
群辉
页面
友链
关于
免责声明
搜索到
249
篇与
绿林寻猫
的结果
2021-12-08
Spring Boot 整合之JavaMail
1.添加依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>本次邮箱测试使用了freemarker模板2.添加配置在 application.properties 中添加spring.mail.host=smtp.qq.com spring.mail.username=********@qq.com #邮箱授权码 spring.mail.password=授权码 spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.starttls.required=true3.创建JavaMailComponentimport org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.mail.MailProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Component; import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import javax.mail.MessagingException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Map; @Component @EnableConfigurationProperties(MailProperties.class) public class JavaMailComponent { private static final String template = "mail.ftl"; @Autowired private FreeMarkerConfigurer freeMarkerConfigurer; @Autowired private JavaMailSender javaMailSender; @Autowired private MailProperties mailProperties; public void sendMail(String email) { Map<String, Object> map = new HashMap<String, Object>(); map.put("email", email); try { // 获取内容 String text = this.getTextByTemplate(template, map); // 发送 this.send(email, text); } catch (Exception e) { e.printStackTrace(); } } private String getTextByTemplate(String template, Map<String, Object> model) throws Exception { return FreeMarkerTemplateUtils .processTemplateIntoString(this.freeMarkerConfigurer.getConfiguration().getTemplate(template), model); } private String send(String email, String text) throws MessagingException, UnsupportedEncodingException { MimeMessage message = this.javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); InternetAddress from = new InternetAddress(); from.setAddress(this.mailProperties.getUsername()); from.setPersonal("Java记", "UTF-8"); helper.setFrom(from); helper.setTo(email); helper.setSubject("SpringBoot 发送的第一封邮件"); helper.setText(text, true); this.javaMailSender.send(message); return text; } }4.创建邮箱模板在 src/main/resources 下的 template 目录下创建名为 mail.ftl 的文件,其内容如下:<!DOCTYPE html> <html lang="zh"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <div style="width: 600px; text-align: left; margin: 0 auto;"> <h1 style="color: #005da7;">Java记</h1> <div style="border-bottom: 5px solid #005da7; height: 2px; width: 100%;"></div> <div style="border: 1px solid #005da7; font-size: 16px; line-height: 50px; padding: 20px;"> <div>${email},您好!</div> <div> 这是个测试 </div> <div> 想了解更多信息,请访问 <a href="https://www.javaj.work">https://www.javaj.work</a> </div> </div> </div> </body> </html>5.测试 @RunWith(SpringRunner.class) @SpringBootTest public class MailTest { @Autowired private JavaMailComponent javaMailComponent; @Test public void test() { this.javaMailComponent.sendMail("********@qq.com"); } }运行结果如下:
2021年12月08日
116 阅读
0 评论
0 点赞
2021-12-08
Spring Boot 整合之文件上传与下载(本地及网络url下载)
1.导入依赖 <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>2.编写封装类 返回信息public class FileInfo { private String path; public FileInfo(String path) { this.path = path; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } }3.编写controller 实现文件上传与下载3.1创建@RestController @RequestMapping("/file") public class FileController { /** * 上传图片 * @param file * @param req * @return * @throws Exception */ @PostMapping public FileInfo upload(MultipartFile file,HttpServletRequest req) throws Exception { System.out.println(file.getName()); System.out.println(file.getOriginalFilename());//原图片名 System.out.println(file.getSize());//大小 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); //图片名 String fileName = URLEncoder.encode(file.getOriginalFilename(), "UTF-8"); fileName=sdf.format(new Date())+fileName.substring(fileName.lastIndexOf('.')); //路径 String path=req.getSession().getServletContext().getRealPath("/")+ "upload\\"; File localFile = new File(path, fileName); file.transferTo(localFile); //返回json格式 return new FileInfo(localFile.getAbsolutePath()); } /** * 下载图片 * @param id * @param request * @param response */ @GetMapping("/{id}")//id为要下载的图片名:123.jsp public void download(@PathVariable String id, HttpServletRequest request, HttpServletResponse response) { String path=request.getSession().getServletContext().getRealPath("/")+ "upload\\"; //根据url获取输入流 //URL url = new URL(zipUrl); //HttpURLConnection conn = (HttpURLConnection)url.openConnection(); //设置超时间为3秒 //conn.setConnectTimeout(3*1000); //防止屏蔽程序抓取而返回403错误 //conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //得到输入流 //InputStream inputStream = conn.getInputStream(); //------------------------------------------- //下载 try (InputStream inputStream = new FileInputStream(new File(path, id )); OutputStream outputStream = response.getOutputStream();) { response.setContentType("application/x-download"); response.addHeader("Content-Disposition", "attachment;filename=" + id); IOUtils.copy(inputStream, outputStream); } catch (Exception e) { e.printStackTrace(); } } }如果路径异常,用以下方法获取路径: /** * 获取图片上传路径 * @return * @throws Exception */ public static String getPath() throws Exception { //路径 File path = new File(ResourceUtils.getURL("classpath:").getPath()); if (!path.exists()) { path = new File(""); } //如果上传目录为/static/images/upload/,则可以如下获取 File upload = new File(path.getAbsolutePath(), "static/upload/"); if (!upload.exists()) { upload.mkdirs(); // System.out.println(upload.getAbsolutePath()); //在开发测试模式时,得到地址为:{项目跟目录}/target/static/images/upload/ //在打成jar正式发布时,得到的地址为:{发布jar包目录}/static/images/upload/ } return upload.getAbsolutePath(); }3.2@RestController和@Controller区别@RestController注解相当于@ResponseBody + @Controller合在一起的作用。1) 如果只是使用@RestController注解Controller,则Controller中的方法无法返回jsp页面,或者html,配置的视图解析器 InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。转json请看https://blog.csdn.net/qq_40369944/article/details/838987522) 如果需要返回到指定页面,则需要用 @Controller配合视图解析器InternalResourceViewResolver才行。 如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。4.测试4.1上传4.1.1html:<form action="/file" method="post" enctype="multipart/form-data" > <input type="file" name="file"> <input type="submit" value="ok"> </form>4.1.2页面:4.1.3结果:4.2下载我就直接根据项目中的图片名下载get方式 地址:浏览器下载:
2021年12月08日
192 阅读
0 评论
0 点赞
2021-12-08
Spring Boot 整合之定时任务
前言@Scheduled适用与监听任务较少的,而Quartz适合较多的,为确保可伸缩性,Quartz采用了基于多线程的架构。启动时,框架初始化一套worker线程,这套线程被调度器用来执行预定的作业。这就是Quartz怎样能并发运行多个作业的原理。Quartz依赖一套松耦合的线程池管理部件来管理线程环境。 实现定时器的方式有两种: Scheduled:spring 3.0 后自带的定时器 Quartz:第三放定时器框架 1.Scheduled1.1创建任务类import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.scheduling.annotation.Async; import java.util.Date; @Component public class Schedule { @Async @Scheduled(fixedRate = 2000) public void task() { System.out.println("启动定时任务:" + new Date()); } }使用 @Scheduled 定义任务执行时间,代码中表示每隔 2 秒执行一次任务。1.2启动定时任务在启动类上添加@EnableScheduling测试结果:2.Quartz2.1导入依赖 <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.2.1</version> </dependency>2.2创建定时任务类import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.util.Date; public class MyJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("========quartz 测试=========="+new Date()); } }2.3创建配置类import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.JobDetailFactoryBean; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean; @Configuration public class QuartzConfiguration { /** * Job 工厂 * @return */ @Bean public JobDetailFactoryBean jobDetailFactoryBean() { JobDetailFactoryBean factory = new JobDetailFactoryBean(); factory.setJobClass(MyJob.class); return factory; } /** * Trigger 工厂 * @return */ @Bean public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactory) { SimpleTriggerFactoryBean factory = new SimpleTriggerFactoryBean(); factory.setJobDetail(jobDetailFactory.getObject()); // 执行间隔时间 factory.setRepeatInterval(5000); // 重复执行次数 factory.setRepeatCount(3); return factory; } /** * Trigger 工厂 * @return */ @Bean public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactory) { CronTriggerFactoryBean factory = new CronTriggerFactoryBean(); factory.setJobDetail(jobDetailFactory.getObject()); factory.setCronExpression("0/5 * * * * ?"); return factory; } @Bean public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactory){ SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setTriggers(cronTriggerFactory.getObject()); return factory; } }同样地,需要在 Spring Boot 的启动类上添加 @EnableScheduling 后,启动项目即可。测试结果:2.4依赖注入问题实际开发中,任务类需要注入业务组件来执行定时任务,如下:public class MyJob implements Job { @Autowired private UserDao userDao; @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //添加 User user1 = new User(); user1.setuName("李四"); int i = userDao.insertUser(user1); System.out.println(i); //查询 User user = userDao.getUserById(1); System.out.println(user); } }但是MyJob 生命周期并没有被 Spring 容器管理,因此无法注入 UserService,当定时器执行任务时会报空指针异常。解决方案:自定义任务工厂,重写创建任务实例的方法:import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.scheduling.quartz.AdaptableJobFactory; import org.springframework.stereotype.Component; @Component("customAdaptableJobFactory") public class CustomAdaptableJobFactory extends AdaptableJobFactory { @Autowired private AutowireCapableBeanFactory autowireCapableBeanFactory; @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { Object object = super.createJobInstance(bundle); // 将任务实例纳入 Spring 容器中 this.autowireCapableBeanFactory.autowireBean(object); return object; } }修改QuartzConfiguration类 的 Scheduler 实现:原:@Bean public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactory){ SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setTriggers(cronTriggerFactory.getObject()); return factory; }改:@Bean public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactory,CustomAdaptableJobFactory customAdaptableJobFactory){ SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setTriggers(cronTriggerFactory.getObject()); factory.setJobFactory(customAdaptableJobFactory); return factory; }测试结果:
2021年12月08日
418 阅读
0 评论
0 点赞
2021-12-08
Spring Boot 整合之Redis
在添加 redis 依赖包启动项目后,Spring Boot 会自动配置 RedisCacheManger 和 RedisTemplate 的 Bean。如果开发者不想使用 Spring Boot 写好的 Redis 缓存,而是想使用其 API 自己实现缓存功能、消息队列或分布式锁之类的需求时,可以继续往下浏览。Spring Data Redis 为我们提供 RedisTemplate 和 StringRedisTemplate 两个模板进行数据操作,它们主要 的访问方法如下:方法说明opsForValue()操作简单属性的数据opsForList()操作含有 list 的数据opsForSet()操作含有 set 的数据opsForZSet()操作含有 zset 的数据opsForHash()操作含有 hash 的数据1.导入依赖 <!--redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>2.配置连接属性# redis 配置 spring.redis.host=47.106.8.233 spring.redis.port=6379 spring.redis.password=redis123 # 缓存过期时间,单位毫秒 spring.cache.redis.time-to-live=60000s3.创建RedisDao@Component public class RedisDao { @Autowired private StringRedisTemplate stringRedisTemplate; public void set(String key, String value) { this.stringRedisTemplate.opsForValue().set(key, value); } public String get(String key) { return this.stringRedisTemplate.opsForValue().get(key); } public void delete(String key) { this.stringRedisTemplate.delete(key); } }4.测试@RunWith(SpringRunner.class) @SpringBootTest public class RedisDaoTest { @Autowired private RedisDao redisDao; @Test public void testSet() { String key = "name"; String value = "zhangsan"; this.redisDao.set(key, value); } @Test public void testGet() { String key = "name"; String value = this.redisDao.get(key); System.out.println(value); } @Test public void testDelete() { String key = "name"; this.redisDao.delete(key); } }
2021年12月08日
272 阅读
0 评论
0 点赞
2021-12-08
Spring Boot 整合之Fastjson
1.导入依赖<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.51</version> </dependency> 2.创建管理类WebConfig@Configuration public class WebConfig { @Bean public HttpMessageConverters fastJsonHttpMessageConverters() { FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter(); FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat); fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig); HttpMessageConverter<?> converter = fastJsonHttpMessageConverter; return new HttpMessageConverters(converter); } }3.创建测试实体类public class Test_Table { private Integer id; private String username; private Date birthday; }getter 和 setter 此处省略。4.创建Controller@Controller @RequestMapping("fastjson") public class FastJsonController{ @RequestMapping("/test") @ResponseBody public Test_Table test() { Test_Table test_table = new Test_Table(); test_table.setId(1); test_table.setUsername("汤姆"); test_table.setBirthday(new Date()); return test_table; } }结果如下:乱码,在@RequestMapping添加 @RequestMapping(value = "/test",produces="text/html;charset=UTF-8") 日期是毫秒数,我们在 User 类中使用 Fastjson 的注解,如下内容: @JSONField(format="yyyy-MM-dd HH:mm:ss") private Date birthday;再次测试,结果如下: 当日期格式与我们修改的内容格式一致,说明 Fastjson 整合成功。
2021年12月08日
323 阅读
0 评论
0 点赞
2021-12-08
Spring Boot 整合之Mybatis
1.引入Mybatis、MySQL依赖注意:这里不引入spring-boot-starter-jdbc依赖,是由于mybatis-spring-boot-starter中已经包含了此依赖。 <!-- springboot,mybatis 整合包 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency>MyBatis-Spring-Boot-Starter依赖将会提供如下: 自动检测现有的DataSource。 将创建并注册SqlSessionFactory的实例,该实例使用SqlSessionFactoryBean将该DataSource作为输入进行传递。 将创建并注册从SqlSessionFactory中获取的SqlSessionTemplate的实例。 自动扫描您的mappers,将它们链接到SqlSessionTemplate并将其注册到Spring上下文,以便将它们注入到您的bean中。 就是说,使用了该Starter之后,只需要定义一个DataSource即可(application.properties中可配置),它会自动创建使用该DataSource的SqlSessionFactoryBean以及SqlSessionTemplate。会自动扫描你的Mappers,连接到SqlSessionTemplate,并注册到Spring上下文中。2.配置数据库连接:在 application.properties 中添加:#数据连接 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=root123 # mybatis 配置 mybatis.config-location=classpath:mybatis/mybatis-config.xml mybatis.mapper-locations=classpath:mybatis/mapper/*.xml3.在 src/main/resources 下创建 mybatis 文件夹,并在 mybatis 文件夹中创建 "mybatis-config.xml" 配置文件,内容如下:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!-- 获取数据库自增主键值 --> <setting name="useGeneratedKeys" value="true"/> <!-- 使用列别名替换列名,默认为 true --> <setting name="useColumnLabel" value="true"/> <!-- 开启驼峰命名转换:Table(create_time) => Entity(createTime) --> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> </configuration>mybatis 文件夹下再创建一个 "mapper" 文件夹,里边存放 Mpper 接口对应的 mapper 映射文件。4.测试4.1建表CREATE TABLE t_user( u_id INT PRIMARY KEY auto_increment COMMENT "ID", u_name VARCHAR(20) NOT NULL COMMENT "用户姓名" )COMMENT="用户"4.2实体类package club.lygangdai.pojo; public class User { private Integer uId; private String uName; }此处省略setter和getter4.3Mapper接口package club.lygangdai.dao; import club.lygangdai.pojo.User; import org.apache.ibatis.annotations.Mapper; @Mapper public interface UserDao { int insertUser(User user); User getUserById(Integer uid); int updateUser(User user); int deleteUserById(Integer uid); }Mapper 接口需要添加 @Mapper 注解,如果不想使用该注解,可以在启动类上使用 @MapperScan 配置 Mapper 接口路径@SpringBootApplication @MapperScan("club.lygangdai.dao") public class SpringbootMybatisJspApplication { public static void main(String[] args) { SpringApplication.run(SpringbootMybatisJspApplication.class, args); } } mybatis/mapper/UserMapper.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="club.lygangdai.dao.UserDao"> <insert id="insertUser" parameterType="club.lygangdai.pojo.User"> insert into t_user(u_name) values(#{uName}) </insert> <select id="getUserById" parameterType="java.lang.Integer" resultType="club.lygangdai.pojo.User"> select u_id,u_name from t_user where u_id = #{uId} </select> <update id="updateUser" parameterType="club.lygangdai.pojo.User"> update t_user set u_name = #{uName} where u_id = #{uId} </update> <delete id="deleteById" parameterType="java.lang.Integer"> delete from t_user where u_id = #{uId} </delete> </mapper>4.4测试4.4.1创建controller@Controller @RequestMapping("user") public class UserController { @Resource private UserDao userDao; @RequestMapping(value = "getUser",produces="text/html;charset=UTF-8") @ResponseBody public User getUser(){ User user = userDao.getUserById(1); return user; } } 注:返回的是json格式,我之前已做配置转json请看https://blog.csdn.net/qq_40369944/article/details/83898752数据库添加一条默认数据查询结果:
2021年12月08日
259 阅读
0 评论
0 点赞
2021-12-08
Spring Boot 整合之模板引擎(jsp、Freemarker 、Thymeleaf )
整合JSP模板 添加依赖创建 maven 工程,在 pom.xml 文件中添加如下依赖:<dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency>创建目录和配置文件1. JSP页面放在:/src/main/webapp/WEB-INF/jsp/目录下(webapp/WEB-INF/jsp 没有就自己创建),如:/src/main/webapp/WEB-INF/jsp/index.jsp 2. CSS或JavaScript之类的静态文件:/src/main/resources/static/目录下,如:/src/main/resources/static/css/main.css 3. 对于属性文件放在:/src/main/resources/目录下,如:/src/main/resources/application.properties 配置application.properties只需要添加这2个就可以了,如下: #页面默认前缀目录spring.mvc.view.prefix=/WEB-INF/jsp/#页面默认后缀目录spring.mvc.view.suffix=.jsp 或在application.yml中:spring节点下面: spring: mvc: view: prefix: /WEB-INF/jsp/ suffix: .jsp 创建JSP页面文件夹在src/main/webapp中的WEB-INF/下创建jsp文件夹,用于存放jsp页面文件。 <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <br> ${map} </body> </html> 编写Controllerpackage club.lygangdai.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import java.util.Map; /** * @author Uncle Liu * @ClassName: TestController * @Description: TODO(类说明 :) * @date 2018/11/7 11:31 */ @Controller @RequestMapping("/jsp") public class TestController { @RequestMapping("/index") public String hello(Map<String,Object> map) { map.put("map", "Hell"); return "index"; } }结果如下: 整合Freemarker 模板添加 Freemarker 依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> 添加 Freemarker 模板配置在 application.properties 中添加如下内容:spring.freemarker.allow-request-override=false spring.freemarker.cache=true spring.freemarker.check-template-location=true spring.freemarker.charset=UTF-8 spring.freemarker.content-type=text/html spring.freemarker.expose-request-attributes=false spring.freemarker.expose-session-attributes=false spring.freemarker.expose-spring-macro-helpers=false spring.freemarker.prefix= spring.freemarker.suffix=.ftl上述配置都是默认值。编写Controllerpackage club.lygangdai.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import java.util.Map; /** * @author Uncle Liu * @ClassName: FreemarkerController * @Description: TODO(类说明 :) * @date 2018/11/7 11:32 */ @Controller @RequestMapping("/freemarker") public class FreemarkerController{ @RequestMapping("/hello") public String hello(Map<String,Object> map) { map.put("map", "Hell Freemarker"); return "freemarker"; } }在 templates 目录中创建名为 freemarker .ftl 文件,内容如下:<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>Document</title> <link href="/css/index.css" rel="stylesheet"/> </head> <body> <div class="container"> <h2>${map}</h2> </div> </body> </html>结果如下:整合Thymeleaf 模板添加 Thymeleaf依赖<!--thymeleaf--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>添加 Thymeleaf模板配置在 application.properties 中添加如下内容:#thymeleaf模板 spring.thymeleaf.cache=true spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=.html spring.thymeleaf.mode=HTML5 spring.thymeleaf.encoding=UTF-8 spring.thymeleaf.servlet.content-type=text/html上述配置都是默认值。编写Controllerpackage club.lygangdai.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import java.util.Map; @Controller @RequestMapping("thymeleaf") public class ThymeleafController { @RequestMapping("thymeleaf") public String hello(Map<String,Object> map) { map.put("map", "Hello Thymeleaf"); return "thymeleaf"; } }在 templates 目录中创建名为 thymeleaf.html 文件,内容如下:<!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2 th:text="${map}"></h2> </body> </html>结果如下:
2021年12月08日
335 阅读
0 评论
0 点赞
2021-12-08
Spring MVC利用Ajax上传图片
html<input type="file" onchange="imageUpload(this)" class="form-control" placeholder="点击按钮选择图片"id="pictureUpload">Ajaxfunction imageUpload(obj) { //判断图片格式 var fileName=obj.value; var suffixIndex=fileName.lastIndexOf("."); var suffix=fileName.substring(suffixIndex+1).toUpperCase(); if(suffix!="BMP"&&suffix!="JPG"&&suffix!="JPEG"&&suffix!="PNG"&&suffix!="GIF"){ layer.msg( "请上传图片(格式BMP、JPG、JPEG、PNG、GIF等)!"); var file = $("#pictureUpload"); file.after(file.clone().val("")); file.remove(); return; } var formData = new FormData(); formData.append('file', $('#pictureUpload')[0].files[0]); //添加图片信息的参数 $.ajax({ type: "POST", url: "/fileUploadPage.do", data:formData, cache: false, //上传文件不需要缓存 processData: false,// 告诉jQuery不要去处理发送的数据 contentType: false,// 告诉jQuery不要去设置Content-Type请求头 encType:"multipart/form-data", success: function(data) { alert(data) } }); }Controller @RequestMapping(value = "/fileUploadPage.do", method = RequestMethod.POST) @ResponseBody public String upload(HttpServletRequest req) throws Exception{ MultipartHttpServletRequest mreq = (MultipartHttpServletRequest)req; MultipartFile file = mreq.getFile("file"); String fileName = file.getOriginalFilename(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); String name=req.getSession().getServletContext().getRealPath("/")+ "upload\\"+sdf.format(new Date())+fileName.substring(fileName.lastIndexOf('.')); FileOutputStream fos = new FileOutputStream(name); fos.write(file.getBytes()); fos.flush(); fos.close(); return name; }在spring.xml中添加 <!--配置MultipartResolver:用于处理表单中的file--> <!-- 文件上传配置,这里id的名称固定写法 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"></property> <!--请求的编码格式--> <property name="maxUploadSize" value="102400000"></property> <!--文件最大大小(字节) 1024*1024*50=50M--> <property name="resolveLazily" value="true"/> <!--resolveLazily属性启用是为了推迟文件解析,以便捕获文件大小异常--> <property name="uploadTempDir" value="upload"></property> <!--指定上传文件的临时文件夹,请在项目中创建好目录。--> </bean>
2021年12月08日
139 阅读
0 评论
0 点赞
2021-12-08
Spring MVC EL表达式不能使用问题
1.在jsp页面添加 isELIgnored="false",EL是关闭的,必须手动打开<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false"%>2.更改web.xml文件(推荐使用)<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">这样在运行项目,在页面就可以获取${name}里的值了
2021年12月08日
139 阅读
0 评论
0 点赞
2021-12-08
Spring Cloud入门之Eureka(一)
目录1.前言2.介绍3.搭建注册中心3.1 创建Spring Boot项目3.2导入依赖3.3 application.yml 配置参数3.4开启注册中心功能4.实战演练4.1 user-api 项目部分代码(服务提供)4.1.1添加依赖4.1.2配置参数4.1.3服务接口4.1.4开启服务注册功能4.2user-web 项目部分代码(服务消费)4.2.1添加依赖4.2.2配置参数4.2.3客户端4.2.4开启服务发现功能5.Eureka 集群5.1application.yml 文件需要进行如下修改:6.Eureka 与 Zookeeper 的区别6.1 CAP 理论6.2 Zookeeper 保证 CP6.3 Eureka 保证 AP7.源码地址1.前言Spring Cloud 是一系列框架的有序集合。它利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 Spring Boot 的开发风格做到一键启动和部署。2.介绍Eureka 是 Netflix 的子模块,它是一个基于 REST 的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册和发现对于微服务架构而言,是非常重要的。有了服务发现和注册,只需要使用服务的标识符就可以访问到服务,而不需要修改服务调用的配置文件。该功能类似于 Dubbo 的注册中心,比如 Zookeeper。Eureka 采用了 CS 的设计架构。Eureka Server 作为服务注册功能的服务端,它是服务注册中心。而系统中其他微服务则使用 Eureka 的客户端连接到 Eureka Server 并维持心跳连接。其运行原理如下图:由图可知,Eureka 的运行原理和 Dubbo 大同小异, Eureka 包含两个组件: Eureka Server 和 Eureka Client。Eureka Server 提供服务的注册服务。各个服务节点启动后会在 Eureka Server 中注册服务,Eureka Server 中的服务注册表会存储所有可用的服务节点信息。Eureka Client 是一个 Java 客户端,用于简化 Eureka Server 的交互,客户端同时也具备一个内置的、使用轮询负载算法的负载均衡器。在应用启动后,向 Eureka Server 发送心跳(默认周期 30 秒)。如果 Eureka Server 在多个心跳周期内没有接收到某个节点的心跳,Eureka Server 会从服务注册表中将该服务节点信息移除。3.搭建注册中心3.1 创建Spring Boot项目3.2导入依赖(注意Spring Boot 与 SpringCloud 有版本兼容关系,如果引用版本不对应,项目启动会报错)<dependencies> <!-- eureka 服务端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.1.0.RELEASE</version> </dependency></dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR1</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>3.3 application.yml 配置参数server: port: 9000 eureka: instance: hostname: localhost # eureka 实例名称 client: register-with-eureka: false # 不向注册中心注册自己 fetch-registry: false # 是否检索服务 service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 注册中心访问地址3.4开启注册中心功能在启动类上添加 @EnableEurekaServer 注解。@EnableEurekaServer@SpringBootApplicationpublic class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }启动项目,访问http://localhost:9000/ ,可看到 Eureka 服务监控界面,如下:4.实战演练了解 Eureka 的环境搭建后,我们需要进行实战直观的感受 Eureka 的真正作用,这样才能清楚掌握和学习 Eureka 。我们再创建两个 Spring Boot 项目,一个名为 user-api ,用于提供接口服务,另一个名为 user-web,用于调用 user-api 接口获取数据与浏览器交互。服务实例端口描述eureka9000注册中心(Eureka 服务端)user-api8081服务提供者(Eureka 客户端)user-web80服务消费者,与浏览器端交互(Eureka 客户端)4.1 user-api 项目部分代码(服务提供)4.1.1添加依赖同样主要版本问题 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- eureka 客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.1.0.RELEASE</version> </dependency>4.1.2配置参数server: port: 8081 spring: application: name: user-api eureka: instance: instance-id: user-api-8081 prefer-ip-address: true # 访问路径可以显示 IP client: service-url: defaultZone: http://localhost:9000/eureka/ # 注册中心访问地址注意:http://localhost:9000/eureka/ 就是注册中心的地址。4.1.3服务接口public interface UserService { String getUserName(); }@Servicepublic class UserServiceImpl implements UserService { @Override public String getUserName() { return "张三"; } }@RestController@RequestMapping("/user")public class UserController { @Autowired private UserService userService; @RequestMapping("/getname") public String get() { return this.userService.getUserName(); } }注意:该 controller 是给 user-web 使用的(内部服务),不是给浏览器端调用的。4.1.4开启服务注册功能在启动类上添加 @EnableEurekaClient 注解。@EnableEurekaClient@SpringBootApplicationpublic class UserApiApplication { public static void main(String[] args) { SpringApplication.run(UserApiApplication.class, args); } }启动项目完成后,浏览器访问 http://localhost:9000 查看 Eureka 服务监控界面 ,如下图:从图可知,user 相关服务信息已经注册到 Eureka 服务中了。补充:在上图中,我们还看到一串红色的字体,那是因为 Eureka 启动了自我保护的机制。当 EurekaServer 在短时间内丢失过多客户端时(可能发生了网络故障),EurekaServer 将进入自我保护模式。进入该模式后,EurekaServer 会保护服务注册表中的信息不被删除。当网络故障恢复后,EurekaServer 会自动退出自我保护模式。4.2user-web 项目部分代码(服务消费)4.2.1添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- eureka 客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.1.0.RELEASE</version> </dependency>4.2.2配置参数server: port: 80 spring: application: name: user-web eureka: client: register-with-eureka: false # 不向注册中心注册自己 fetch-registry: true # 是否检索服务 service-url: defaultZone: http://localhost:9000/eureka/ # 注册中心访问地址4.2.3客户端@Configurationpublic class RestConfiguration { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } }@RestController@RequestMapping("/user")public class UserController { @Autowired private RestTemplate restTemplate; @Resource private DiscoveryClient client; @RequestMapping("/getname") public User get() throws Exception { //getForObject() 发送一个HTTP GET请求,返回的请求体将映射为一个对象 //user-api 为调用的uri(服务提供者(Eureka 客户端)地址)在eureka上注册的application.name return restTemplate.getForObject( "http://user-api/user/getname",User.class); } }4.2.4开启服务发现功能在启动类上添加 @EnableDiscoveryClient 注解。@EnableDiscoveryClient@SpringBootApplicationpublic class UserWebApplication { public static void main(String[] args) { SpringApplication.run(UserWebApplication.class, args); } }启动项目后,使用浏览器访问 user-web 项目接口,运行结果如下:数据来源:user-api8081服务提供者(Eureka 客户端)5.Eureka 集群Eureka 作为注册中心,保存了系统服务的相关信息,如果注册中心挂掉,那么系统就瘫痪了。因此,对 Eureka 做集群实现高可用是必不可少的。本次测试使用一台机器部署 Eureka 集群,通过名字和端口区分不同的 eureka 服务。Eureka 名称端口号eureka019001eureka029002准备工作:由于我们使用了http://eureka01 这种写法,需要配一下host。给C:\Windows\System32\drivers\etc下面的hosts文件添加几个配置5.1application.yml 文件需要进行如下修改:server: port: 9001 spring: application: name: eureka-server profiles: active: eureka01 eureka: instance: hostname: eureka01 # eureka 实例名称 client: # register-with-eureka: false # 不向注册中心注册自己 # fetch-registry: false # 是否检索服务 service-url: defaultZone: http://eureka01:9001/eureka/,http://eureka02:9002/eureka/server: port: 9002 spring: application: name: eureka-server profiles: active: eureka02 eureka: instance: hostname: eureka02 # eureka 实例名称 client: # register-with-eureka: false # 不向注册中心注册自己 # fetch-registry: false # 是否检索服务 service-url: defaultZone: http://eureka01:9001/eureka/,http://eureka02:9002/eureka/两个 eureka 服务实例的配置文件修改方式类似,将名称和端口进行修改即可。服务注册的项目中,将 eureka.client.service-url.defaultZone 改成集群的 url 即可。启动一个服务时报错很正常,因为另外一个没有启动com.sun.jersey.api.client.ClientHandlerException: org.apache.http.conn.ConnectTimeoutException: Connect to eureka02:9002 timed out at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:187) ~[jersey-apache-client4-1.19.1.jar:1.19.1] at com.netflix.eureka.cluster.DynamicGZIPContentEncodingFilter.handle(DynamicGZIPContentEncodingFilter.java:48) ~[eureka-core-1.9.8.jar:1.9.8] at com.netflix.discovery.EurekaIdentityHeaderFilter.handle(EurekaIdentityHeaderFilter.java:27) ~[eureka-client-1.9.8.jar:1.9.8] at com.sun.jersey.api.client.Client.handle(Client.java:652) ~[jersey-client-1.19.1.jar:1.19.1] at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682) ~[jersey-client-1.19.1.jar:1.19.1] at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) ~[jersey-client-1.19.1.jar:1.19.1] at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:570) ~[jersey-client-1.19.1.jar:1.19.1] at com.netflix.eureka.transport.JerseyReplicationClient.submitBatchUpdates(JerseyReplicationClient.java:116) ~[eureka-core-1.9.8.jar:1.9.8] at com.netflix.eureka.cluster.ReplicationTaskProcessor.process(ReplicationTaskProcessor.java:80) ~[eureka-core-1.9.8.jar:1.9.8] at com.netflix.eureka.util.batcher.TaskExecutors$BatchWorkerRunnable.run(TaskExecutors.java:193) [eureka-core-1.9.8.jar:1.9.8] at java.lang.Thread.run(Thread.java:748) [na:1.8.0_201] Caused by: org.apache.http.conn.ConnectTimeoutException: Connect to eureka02:9002 timed out at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:123) ~[httpclient-4.5.8.jar:4.5.8] at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180) ~[httpclient-4.5.8.jar:4.5.8] at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:144) ~[httpclient-4.5.8.jar:4.5.8] at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:134) ~[httpclient-4.5.8.jar:4.5.8] at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:605) ~[httpclient-4.5.8.jar:4.5.8] at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:440) ~[httpclient-4.5.8.jar:4.5.8] at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835) ~[httpclient-4.5.8.jar:4.5.8] at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:118) ~[httpclient-4.5.8.jar:4.5.8] at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) ~[httpclient-4.5.8.jar:4.5.8] at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:173) ~[jersey-apache-client4-1.19.1.jar:1.19.1] ... 10 common frames omitted效果如下:6.Eureka 与 Zookeeper 的区别两者都可以充当注册中心的角色,且可以集群实现高可用,相当于小型的分布式存储系统。6.1 CAP 理论CAP 分别为 consistency(强一致性)、availability(可用性) 和 partition toleranc(分区容错性)。理论核心:一个分布式系统不可能同时很好的满足一致性、可用性和分区容错性这三个需求。因此,根据 CAP 原理将 NoSQL 数据库分成满足 CA 原则、满足 CP 原则和满足 AP 原则三大类: CA:单点集群,满足一致性,可用性的系统,通常在可扩展性上不高 CP: 满足一致性,分区容错性的系统,通常性能不是特别高 AP: 满足可用性,分区容错性的系统,通过对一致性要求较低 简单的说:CAP 理论描述在分布式存储系统中,最多只能满足两个需求。6.2 Zookeeper 保证 CP当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟前的注册信息,但不能接受服务直接挂掉不可用了。因此,服务注册中心对可用性的要求高于一致性。但是,zookeeper 会出现一种情况,当 master 节点因为网络故障与其他节点失去联系时,剩余节点会重新进行 leader 选举。问题在于,选举 leader 的时间较长,30 ~ 120 秒,且选举期间整个 zookeeper 集群是不可用的,这期间会导致注册服务瘫痪。在云部署的环境下,因网络问题导致 zookeeper 集群失去 master 节点的概率较大,虽然服务能最终恢复,但是漫长的选举时间导致注册服务长期不可用是不能容忍的。6.3 Eureka 保证 APEureka 在设计上优先保证了可用性。EurekaServer 各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和发现服务。而 Eureka 客户端在向某个 EurekaServer 注册或发现连接失败时,会自动切换到其他 EurekaServer 节点,只要有一台 EurekaServer 正常运行,就能保证注册服务可用,只不过查询到的信息可能不是最新的。除此之外,EurekaServer 还有一种自我保护机制,如果在 15 分钟内超过 85% 的节点都没有正常的心跳,那么 EurekaServer 将认为客户端与注册中心出现网络故障,此时会出现一下几种情况: EurekaServer 不再从注册列表中移除因为长时间没有收到心跳而应该过期的服务 EurekaServer 仍然能够接收新服务的注册和查询请求,但不会被同步到其他节点上 当网络稳定时,当前 EurekaServer 节点新的注册信息会同步到其他节点中 因此,Eureka 可以很好的应对因网络故障导致部分节点失去联系的情况,而不会向 Zookeeper 那样是整个注册服务瘫痪。7.源码地址源码下载以上为本人实际测试写下的,如有不足地方请指出。
2021年12月08日
264 阅读
0 评论
0 点赞
1
...
5
6
7
...
25