@EnableSwagger2WebMvc
@ConditionalOnWebApplication
@Import(BeanValidatorPluginsConfiguration.class)
public class Knife4jConfig
{
/**
* 开发、测试环境接口文档打开
*
* @return
* @see [类、类#方法、类#成员]
*/
@Bean
Docket createRestApi()
{
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.enable(true)
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any()) // 包下的类,生成接口文档
.build()
.securitySchemes(security());
}
private ApiInfo apiInfo()
{
return new ApiInfoBuilder().title("数据接口API").description("接口文档").termsOfServiceUrl("http://00fly.online/").version("1.0.0").build();
}
private List<ApiKey> security()
{
return Collections.singletonList(new ApiKey("token", "token", "header"));
}
}
//goto src\main\java\com\fly\core\config\WebMvcConfig.java
package com.fly.core.config;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.fly.core.auth.AuthInterceptor;
/**
*
* mvc配置
*
* @author 00fly
* @version [版本号, 2021年4月23日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
@Configuration
@ConditionalOnWebApplication
public class WebMvcConfig implements WebMvcConfigurer
{
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters)
{
converters.add(stringHttpMessageConverter());
converters.add(mappingJackson2HttpMessageConverter());
}
@Override
public void configureContentNegotiation(final ContentNegotiationConfigurer configurer)
{
configurer.defaultContentType(MediaType.APPLICATION\_JSON);
configurer.ignoreUnknownPathExtensions(false);
configurer.favorPathExtension(true);
configurer.favorParameter(false);
final Map<String, MediaType> mediaTypes = new ConcurrentHashMap<>(3);
mediaTypes.put("atom", MediaType.APPLICATION\_ATOM\_XML);
mediaTypes.put("html", MediaType.TEXT\_HTML);
mediaTypes.put("json", MediaType.APPLICATION\_JSON);
configurer.mediaTypes(mediaTypes);
}
@Bean
StringHttpMessageConverter stringHttpMessageConverter()
{
return new StringHttpMessageConverter();
}
@Bean
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter()
{
final MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
final List<MediaType> list = new ArrayList<>();
list.add(MediaType.APPLICATION\_JSON);
list.add(MediaType.APPLICATION\_XML);
list.add(MediaType.TEXT\_PLAIN);
list.add(MediaType.TEXT\_HTML);
list.add(MediaType.TEXT\_XML);
messageConverter.setSupportedMediaTypes(list);
return messageConverter;
}
/\*\*
* 等价于mvc中<mvc:view-controller path=“/” view-name=“redirect:index” />
* 等价于mvc中<mvc:view-controller path=“/index” view-name=“index.html” />
*
* @param registry
*/
@Override
public void addViewControllers(final ViewControllerRegistry registry)
{
registry.addViewController(“/”).setViewName(“redirect:index”);
// registry.addViewController(“/index”).setViewName(“index.html”);
}
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(authInterceptor).addPathPatterns("/rest/file/\*\*", "/file/\*\*");
}
}
//goto src\main\java\com\fly\core\exception\GlobalExceptionHandler.java
package com.fly.core.exception;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.fly.web.entity.JsonResult;
import lombok.extern.slf4j.Slf4j;
/**
* 统一异常处理器
*
* @author 00fly
* @version [版本号, 2018-09-11]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler
{
@ExceptionHandler(value = Exception.class)
public JsonResult<?> handleBadRequest(Exception exception)
{
// JSR303参数校验异常
if (exception instanceof BindException)
{
BindingResult bindingResult = ((BindException)exception).getBindingResult();
if (null != bindingResult && bindingResult.hasErrors())
{
List errMsg = new ArrayList<>();
bindingResult.getFieldErrors().stream().forEach(fieldError -> {
errMsg.add(fieldError.getDefaultMessage());
});
Collections.sort(errMsg);
return JsonResult.error(StringUtils.join(errMsg, “,”));
}
}
if (exception instanceof MethodArgumentNotValidException)
{
BindingResult bindingResult = ((MethodArgumentNotValidException)exception).getBindingResult();
if (null != bindingResult && bindingResult.hasErrors())
{
List errMsg = new ArrayList<>();
bindingResult.getFieldErrors().stream().forEach(fieldError -> {
errMsg.add(fieldError.getDefaultMessage());
});
return JsonResult.error(StringUtils.join(errMsg, “,”));
}
}
// 其余情况
log.error(“Error: handleBadRequest StackTrace : {}”, exception);
return JsonResult.error(StringUtils.defaultString(exception.getMessage(), “系统异常,请联系管理员”));
}
}
//goto src\main\java\com\fly\core\exception\ValidateException.java
package com.fly.core.exception;
public class ValidateException extends RuntimeException
{
private static final long serialVersionUID = -939208231165751812L;
public ValidateException()
{
super();
}
public ValidateException(String message)
{
super(message);
}
}
//goto src\main\java\com\fly\core\qr\BufferedImageLuminanceSource.java
package com.fly.core.qr;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import com.google.zxing.LuminanceSource;
public class BufferedImageLuminanceSource extends LuminanceSource
{
private BufferedImage image;
private int left;
private int top;
public BufferedImageLuminanceSource(BufferedImage image)
{
this(image, 0, 0, image.getWidth(), image.getHeight());
}
public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height)
{
super(width, height);
int sourceWidth = image.getWidth();
int sourceHeight = image.getHeight();
if (left + width > sourceWidth || top + height > sourceHeight)
{
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
}
for (int y = top; y < top + height; y++)
{
for (int x = left; x < left + width; x++)
{
if ((image.getRGB(x, y) & 0xFF000000) == 0)
{
image.setRGB(x, y, 0xFFFFFFFF);
}
}
}
this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE\_BYTE\_GRAY);
this.image.getGraphics().drawImage(image, 0, 0, null);
this.left = left;
this.top = top;
}
@Override
public byte[] getRow(int y, byte[] row)
{
if (y < 0 || y >= getHeight())
{
throw new IllegalArgumentException("Requested row is outside the image: " + y);
}
int width = getWidth();
if (row == null || row.length < width)
{
row = new byte[width];
}
image.getRaster().getDataElements(left, top + y, width, 1, row);
return row;
}
@Override
public byte[] getMatrix()
{
int width = getWidth();
int height = getHeight();
int area = width \* height;
byte[] matrix = new byte[area];
image.getRaster().getDataElements(left, top, width, height, matrix);
return matrix;
}
@Override
public boolean isCropSupported()
{
return true;
}
@Override
public LuminanceSource crop(int left, int top, int width, int height)
{
return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);
}
@Override
public boolean isRotateSupported()
{
return true;
}
@Override
public LuminanceSource rotateCounterClockwise()
{
int sourceWidth = image.getWidth();
int sourceHeight = image.getHeight();
AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);
BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE\_BYTE\_GRAY);
Graphics2D g = rotatedImage.createGraphics();
g.drawImage(image, transform, null);
g.dispose();
int width = getWidth();
return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);
}
}
//goto src\main\java\com\fly\core\qr\QRCodeUtil.java
package com.fly.core.qr;
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Hashtable;
import javax.imageio.ImageIO;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.Result;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
public class QRCodeUtil
{
/**
* 二维码尺寸
*/
private static final int QRCODE_SIZE = 300;
/\*\*
* LOGO宽度
*/
private static final int WIDTH = 60;
/\*\*
* LOGO高度
*/
private static final int HEIGHT = 60;
/\*\*
* 给定内容、图标生成二维码图片
*
* @param content 內容
* @param imgURL 图标
* @param needCompress 是否压缩尺寸
* @return
* @throws Exception
* @see [类、类#方法、类#成员]
*/
public static BufferedImage createImage(String content, URL imgURL, boolean needCompress)
throws Exception
{
Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8);
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
if (imgURL == null)
{
return image;
}
// 插入图片
insertImage(image, imgURL, needCompress);
return image;
}
private static void insertImage(BufferedImage source, URL imgURL, boolean needCompress)
throws Exception
{
if (imgURL == null)
{
System.err.println("文件不存在!");
return;
}
Image src = ImageIO.read(imgURL);
int width = src.getWidth(null);
int height = src.getHeight(null);
if (needCompress)
{
// 压缩LOGO
width = Math.min(width, WIDTH);
height = Math.min(height, HEIGHT);
Image image = src.getScaledInstance(width, height, Image.SCALE\_SMOOTH);
BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE\_INT\_RGB);
Graphics g = tag.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
src = image;
}
// 插入LOGO
Graphics2D graph = source.createGraphics();
int x = (QRCODE\_SIZE - width) / 2;
int y = (QRCODE\_SIZE - height) / 2;
graph.drawImage(src, x, y, width, height, null);
Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
graph.setStroke(new BasicStroke(3f));
graph.draw(shape);
graph.dispose();
}
/\*\*
* 解析二维码图
*
* @param file
* @return
* @throws Exception
* @see [类、类#方法、类#成员]
*/
public static String decode(File file)
throws Exception
{
BufferedImage image = ImageIO.read(file);
if (image == null)
{
return null;
}
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Hashtable<DecodeHintType, String> hints = new Hashtable<>();
hints.put(DecodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());
Result result = new MultiFormatReader().decode(bitmap, hints);
return result.getText();
}
/\*\*
* 解析二维码图
*
* @param path
* @return
* @throws Exception
* @see [类、类#方法、类#成员]
*/
public static String decode(String path)
throws Exception
{
return decode(new File(path));
}
}
//goto src\main\java\com\fly\core\utils\TokenUtils.java
package com.fly.core.utils;
import java.util.Date;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class TokenUtils
{
private static String sysToken;
/\*\*
* sysToken有效时间(2小时)
*/
private static Date sysTokenTime;
/\*\*
* 验证token是否合法
*
* @param token
* @return
* @return
*/
public static boolean valide(String token)
{
boolean success = StringUtils.equals(token, getToken());
if (!success)
{
log.info(“------ now valid sysToken is: {}”, sysToken);
}
return success;
}
/\*\*
* 获取sysToken有效时间
*
* @return
*/
public static String getTokenTime()
{
if (sysTokenTime != null)
{
return DateFormatUtils.format(sysTokenTime, “yyyy-MM-dd HH:mm:ss”);
}
return null;
}
/\*\*
* 获取sysToken
*
* @return
* @see [类、类#方法、类#成员]
*/
private static String getToken()
{
Date now = new Date();
if (sysTokenTime == null || now.after(sysTokenTime))
{
sysTokenTime = DateUtils.addHours(now, 2);
sysToken = UUID.randomUUID().toString().replace(“-”, “”);
log.info(“------ now valid sysToken is: {}”, sysToken);
}
return sysToken;
}
}
//goto src\main\java\com\fly\FilesSendBootApplication.java
package com.fly;
import java.net.InetAddress;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class FilesSendBootApplication
{
@Value(“${server.port}”)
String port;
public static void main(String[] args)
{
SpringApplication.run(FilesSendBootApplication.class, args);
}
@Bean
@ConditionalOnWebApplication
CommandLineRunner init()
{
return args -> {
if (SystemUtils.IS\_OS\_WINDOWS)// 防止非windows系统报错,启动失败
{
String ip = InetAddress.getLocalHost().getHostAddress();
String url = "http://" + ip + ":" + port;
Runtime.getRuntime().exec("cmd /c start " + url);
}
};
}
}
//goto src\main\java\com\fly\web\controller\ApiController.java
package com.fly.web.controller;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fly.core.qr.QRCodeUtil;
import com.fly.core.utils.TokenUtils;
import com.fly.web.entity.JsonResult;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
@Api(tags = “系统接口”)
@RestController
@RequestMapping(“/api”)
public class ApiController
{
@Autowired
HttpSession httpSession;
@ApiOperationSupport(order = 10)
@PostMapping("/login")
@ApiOperation("登录系统")
public JsonResult<?> login(String token)
{
if (!TokenUtils.valide(token))
{
return JsonResult.error("token empty or valide failed!");
}
httpSession.setAttribute("token", token);
String date = DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss");
return JsonResult.success(date + " login success!");
}
@ApiOperationSupport(order = 20)
@PostMapping("/logout")
@ApiOperation("退出系统")
public JsonResult<?> logout()
{
httpSession.invalidate();
String date = DateFormatUtils.format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss");
return JsonResult.success(date + " logout success!");
}
@ApiOperation("生成二维码")
@ApiImplicitParam(name = "content", value = "二维码文本", required = true, example = "乡愁是一棵没有年轮的树,永不老去")
@PostMapping(value = "/qr/create", produces = MediaType.IMAGE\_JPEG\_VALUE)
public void index(String content, HttpServletResponse response)
throws Exception
{
if (StringUtils.isNotBlank(content))
{
Resource resource = new ClassPathResource("img/dog.jpg");
URL imgURL = resource.getURL();
BufferedImage image = QRCodeUtil.createImage(content, imgURL, true);
// 输出图象到页面
ImageIO.write(image, "JPEG", response.getOutputStream());
}
}
}
//goto src\main\java\com\fly\web\controller\file\FileController.java
package com.fly.web.controller.file;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import com.fly.core.exception.ValidateException;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping(“/file”)
public class FileController
{
@PostMapping(“/upload”)
public String upload(@RequestParam MultipartFile[] files)
throws IOException
{
if (files == null || files.length == 0)
{
throw new ValidateException(“files is null”);
}
String date = DateFormatUtils.format(System.currentTimeMillis(), “yyyyMMdd”);
String dir = new File(“upload”).getCanonicalPath() + File.separator + date + File.separator;
new File(dir).mkdirs();
// 保存文件
for (MultipartFile file : files)
{
if (StringUtils.isNotBlank(file.getOriginalFilename()))
{
File newFile = new File(dir + file.getOriginalFilename());
FileCopyUtils.copy(file.getInputStream(), new FileOutputStream(newFile));
log.info("###### file upload to: {}", dir);
}
}
return "redirect:/index";
}
@GetMapping(value = "/down/{index}", produces = MediaType.APPLICATION\_OCTET\_STREAM\_VALUE)
public void down(@PathVariable int index, HttpServletResponse response)
throws IOException
{
File dir = new File("upload");
List<File> files = FileUtils.listFiles(dir, null, true).stream().filter(f -> f.isFile()).sorted(Comparator.comparing(File::getAbsolutePath)).collect(Collectors.toList());
if (index >= 0 && index < files.size())
{
File file = files.get(index);
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), StandardCharsets.UTF\_8.name()));
response.setHeader("Cache-Control", "no-store, no-cache");
FileCopyUtils.copy(new FileInputStream(file), response.getOutputStream());
}
}
@GetMapping(value = "/clear")
public String clear()
throws IOException
{
File dir = new File("upload");
FileUtils.cleanDirectory(dir);
return "redirect:/index";
}
@GetMapping(value = "/delete/{index}")
public String delete(@PathVariable int index)
{
File dir = new File("upload");
List<File> files = FileUtils.listFiles(dir, null, true).stream().filter(f -> f.isFile()).sorted(Comparator.comparing(File::getAbsolutePath)).collect(Collectors.toList());
if (index >= 0 && index < files.size())
{
files.get(index).delete();
}
return "redirect:/index";
}
}
//goto src\main\java\com\fly\web\controller\file\RestFileController.java
package com.fly.web.controller.file;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.http.MediaType;
import org.springframework.util.FileCopyUtils;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.fly.core.exception.ValidateException;
import com.fly.web.entity.JsonResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Api(tags = “文件上传、下载接口”)
@RestController
@RequestMapping(“/rest/file”)
public class RestFileController
{
@ApiOperation(“文件下载, index取值 [0, files.length)”)
@ApiImplicitParam(name = “index”, value = “文件索引,起始值0”, required = true, allowableValues = “0,1,2,3,4,5,6,7,8,9,10”)
@GetMapping(value = “/down/{index}”, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void down(@PathVariable int index, HttpServletResponse response)
throws IOException
{
File dir = new File(“upload”);
List files = FileUtils.listFiles(dir, null, true).stream().filter(f -> f.isFile()).sorted(Comparator.comparing(File::getAbsolutePath)).collect(Collectors.toList());
if (index >= 0 && index < files.size())
{
File file = files.get(index);
response.setHeader(“Content-Disposition”, “attachment;filename=” + URLEncoder.encode(file.getName(), StandardCharsets.UTF_8.name()));
response.setHeader(“Cache-Control”, “no-store, no-cache”);
FileCopyUtils.copy(new FileInputStream(file), response.getOutputStream());
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Linux运维工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Linux运维知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加VX:vip1024b (备注Linux运维获取)
为了做好运维面试路上的助攻手,特整理了上百道 【运维技术栈面试题集锦】 ,让你面试不慌心不跳,高薪offer怀里抱!
这次整理的面试题,小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。
本份面试集锦涵盖了
- 174 道运维工程师面试题
- 128道k8s面试题
- 108道shell脚本面试题
- 200道Linux面试题
- 51道docker面试题
- 35道Jenkis面试题
- 78道MongoDB面试题
- 17道ansible面试题
- 60道dubbo面试题
- 53道kafka面试
- 18道mysql面试题
- 40道nginx面试题
- 77道redis面试题
- 28道zookeeper
总计 1000+ 道面试题, 内容 又全含金量又高
- 174道运维工程师面试题
1、什么是运维?
2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?
3、现在给你三百台服务器,你怎么对他们进行管理?
4、简述raid0 raid1raid5二种工作模式的工作原理及特点
5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?
6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?
7、Tomcat和Resin有什么区别,工作中你怎么选择?
8、什么是中间件?什么是jdk?
9、讲述一下Tomcat8005、8009、8080三个端口的含义?
10、什么叫CDN?
11、什么叫网站灰度发布?
12、简述DNS进行域名解析的过程?
13、RabbitMQ是什么东西?
14、讲一下Keepalived的工作原理?
15、讲述一下LVS三种模式的工作过程?
16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?
17、如何重置mysql root密码?
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
kis面试题**
- 78道MongoDB面试题
- 17道ansible面试题
- 60道dubbo面试题
- 53道kafka面试
- 18道mysql面试题
- 40道nginx面试题
- 77道redis面试题
- 28道zookeeper
总计 1000+ 道面试题, 内容 又全含金量又高
- 174道运维工程师面试题
1、什么是运维?
2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?
3、现在给你三百台服务器,你怎么对他们进行管理?
4、简述raid0 raid1raid5二种工作模式的工作原理及特点
5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?
6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?
7、Tomcat和Resin有什么区别,工作中你怎么选择?
8、什么是中间件?什么是jdk?
9、讲述一下Tomcat8005、8009、8080三个端口的含义?
10、什么叫CDN?
11、什么叫网站灰度发布?
12、简述DNS进行域名解析的过程?
13、RabbitMQ是什么东西?
14、讲一下Keepalived的工作原理?
15、讲述一下LVS三种模式的工作过程?
16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?
17、如何重置mysql root密码?
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-FNgSCl9W-1712717207769)]