springboot 简易文件共享工具,拿下offer全凭这套“面试+架构进阶知识点”pdf

@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运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Linux运维知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip1024b (备注Linux运维获取)
img

为了做好运维面试路上的助攻手,特整理了上百道 【运维技术栈面试题集锦】 ,让你面试不慌心不跳,高薪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行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

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)]

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值