271 lines
9.9 KiB
C#
271 lines
9.9 KiB
C#
using System;
|
|
using System.Configuration;
|
|
using System.Data;
|
|
using System.Data.SqlClient;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Net.Http.Headers;
|
|
using System.Text.RegularExpressions;
|
|
using System.Web.Http;
|
|
using DataLinkMesWork2;
|
|
|
|
namespace WebApi
|
|
{
|
|
[RoutePrefix("api/checkimage")]
|
|
public class CheckImageController : ApiController
|
|
{
|
|
private readonly string _defaultRoot = @"D:\\XDCheckImages";
|
|
|
|
public class ImageUploadRequest
|
|
{
|
|
public string ProductCode { get; set; }
|
|
public string Remark { get; set; }
|
|
public string ImageBase64 { get; set; }
|
|
public string FileExt { get; set; }
|
|
}
|
|
|
|
public class ImageDownloadRequest
|
|
{
|
|
public string Path { get; set; }
|
|
}
|
|
|
|
private string GetRootPath()
|
|
{
|
|
string root = null;
|
|
try
|
|
{
|
|
root = ConfigurationManager.AppSettings["XD_CheckImageRootPath"];
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(root))
|
|
{
|
|
root = _defaultRoot;
|
|
}
|
|
|
|
return root;
|
|
}
|
|
|
|
private string SanitizeForPath(string input)
|
|
{
|
|
if (string.IsNullOrEmpty(input)) return string.Empty;
|
|
char[] invalid = Path.GetInvalidFileNameChars();
|
|
var value = input.Trim();
|
|
foreach (var c in invalid)
|
|
{
|
|
value = value.Replace(c.ToString(), string.Empty);
|
|
}
|
|
value = value.Replace("/", string.Empty).Replace("\\", string.Empty);
|
|
return value;
|
|
}
|
|
|
|
private string GetExtensionFromRequest(ImageUploadRequest request)
|
|
{
|
|
string ext = ".jpg";
|
|
if (request == null) return ext;
|
|
|
|
if (!string.IsNullOrWhiteSpace(request.FileExt))
|
|
{
|
|
ext = request.FileExt.Trim();
|
|
if (!ext.StartsWith("."))
|
|
{
|
|
ext = "." + ext;
|
|
}
|
|
return ext;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(request.ImageBase64) &&
|
|
request.ImageBase64.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
try
|
|
{
|
|
var match = Regex.Match(request.ImageBase64, "^data:(?<mime>[^;]+);base64,", RegexOptions.IgnoreCase);
|
|
if (match.Success)
|
|
{
|
|
var mime = match.Groups["mime"].Value.ToLowerInvariant();
|
|
if (mime == "image/png") return ".png";
|
|
if (mime == "image/gif") return ".gif";
|
|
if (mime == "image/bmp") return ".bmp";
|
|
if (mime == "image/webp") return ".webp";
|
|
if (mime == "image/tiff" || mime == "image/tif") return ".tif";
|
|
if (mime == "image/jpeg" || mime == "image/jpg") return ".jpg";
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
return ext;
|
|
}
|
|
|
|
private string GetContentType(string fileName)
|
|
{
|
|
var extension = Path.GetExtension(fileName).ToLowerInvariant();
|
|
if (extension == ".bmp") return "image/bmp";
|
|
if (extension == ".jpg" || extension == ".jpeg") return "image/jpeg";
|
|
if (extension == ".png") return "image/png";
|
|
if (extension == ".gif") return "image/gif";
|
|
if (extension == ".tiff" || extension == ".tif") return "image/tiff";
|
|
if (extension == ".webp") return "image/webp";
|
|
return "application/octet-stream";
|
|
}
|
|
|
|
private bool IsPathSafe(string fullPath)
|
|
{
|
|
try
|
|
{
|
|
var basePath = Path.GetFullPath(GetRootPath());
|
|
var requestedPath = Path.GetFullPath(fullPath);
|
|
return requestedPath.StartsWith(basePath, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[HttpPost]
|
|
[Route("upload")]
|
|
public IHttpActionResult Upload([FromBody] ImageUploadRequest request)
|
|
{
|
|
try
|
|
{
|
|
if (request == null ||
|
|
string.IsNullOrWhiteSpace(request.ProductCode) ||
|
|
string.IsNullOrWhiteSpace(request.Remark) ||
|
|
string.IsNullOrWhiteSpace(request.ImageBase64))
|
|
{
|
|
return Ok(new { success = false, message = "产品编号、备注和图片不能为空" });
|
|
}
|
|
|
|
string productCode = SanitizeForPath(request.ProductCode);
|
|
string remark = SanitizeForPath(request.Remark);
|
|
if (string.IsNullOrEmpty(productCode))
|
|
{
|
|
return Ok(new { success = false, message = "产品编号无效" });
|
|
}
|
|
|
|
string ext = GetExtensionFromRequest(request);
|
|
string base64 = request.ImageBase64.Trim();
|
|
int commaIndex = base64.IndexOf(',');
|
|
if (base64.StartsWith("data:", StringComparison.OrdinalIgnoreCase) && commaIndex > 0)
|
|
{
|
|
base64 = base64.Substring(commaIndex + 1);
|
|
}
|
|
|
|
byte[] bytes;
|
|
try
|
|
{
|
|
bytes = Convert.FromBase64String(base64);
|
|
}
|
|
catch
|
|
{
|
|
return Ok(new { success = false, message = "图片数据格式错误" });
|
|
}
|
|
|
|
var now = DateTime.Now;
|
|
string datePart = now.ToString("yyyyMMdd");
|
|
string timePart = now.ToString("HHmmss");
|
|
|
|
string fileName = string.Format("{0}-{1}-{2}{3}", timePart, productCode, remark, ext);
|
|
string relativePath = string.Format("/{0}/{1}", datePart, fileName);
|
|
|
|
string root = GetRootPath();
|
|
string directory = Path.Combine(root, datePart);
|
|
if (!Directory.Exists(directory))
|
|
{
|
|
Directory.CreateDirectory(directory);
|
|
}
|
|
|
|
string fullPath = Path.Combine(directory, fileName);
|
|
|
|
if (!IsPathSafe(fullPath))
|
|
{
|
|
return Ok(new { success = false, message = "目标路径不安全" });
|
|
}
|
|
|
|
File.WriteAllBytes(fullPath, bytes);
|
|
|
|
string errorMessage;
|
|
var sqlParameters = new SqlParameter[4];
|
|
sqlParameters[0] = new SqlParameter("@产品编号", SqlDbType.NVarChar, 500) { Value = (object)request.ProductCode ?? DBNull.Value };
|
|
sqlParameters[1] = new SqlParameter("@备注", SqlDbType.NVarChar, 500) { Value = (object)request.Remark ?? DBNull.Value };
|
|
sqlParameters[2] = new SqlParameter("@图片路径", SqlDbType.NVarChar, 500) { Value = (object)relativePath ?? DBNull.Value };
|
|
sqlParameters[3] = new SqlParameter("@图片名称", SqlDbType.NVarChar, 500) { Value = (object)fileName ?? DBNull.Value };
|
|
|
|
bool dbOk = DataAccess2.ExecuteStoredProcedure("XD_检测图片上传_增加", ref sqlParameters, out errorMessage);
|
|
if (!dbOk)
|
|
{
|
|
return Ok(new { success = false, message = "图片已保存,但写入数据库失败:" + errorMessage });
|
|
}
|
|
|
|
return Ok(new
|
|
{
|
|
success = true,
|
|
message = "上传成功",
|
|
data = new
|
|
{
|
|
产品编号 = request.ProductCode,
|
|
备注 = request.Remark,
|
|
图片路径 = relativePath,
|
|
图片名称 = fileName
|
|
}
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Ok(new { success = false, message = "服务器错误:" + ex.Message });
|
|
}
|
|
}
|
|
|
|
[HttpPost]
|
|
[Route("download")]
|
|
public IHttpActionResult Download([FromBody] ImageDownloadRequest request)
|
|
{
|
|
try
|
|
{
|
|
if (request == null || string.IsNullOrWhiteSpace(request.Path))
|
|
{
|
|
return Ok(new { success = false, message = "文件路径不能为空" });
|
|
}
|
|
|
|
string root = GetRootPath();
|
|
string relative = request.Path.Replace("\\", "/").Trim();
|
|
if (relative.StartsWith("/"))
|
|
{
|
|
relative = relative.Substring(1);
|
|
}
|
|
string fullPath = Path.Combine(root, relative.Replace('/', Path.DirectorySeparatorChar));
|
|
|
|
if (!IsPathSafe(fullPath) || !File.Exists(fullPath))
|
|
{
|
|
return Ok(new { success = false, message = "文件不存在" });
|
|
}
|
|
|
|
var fileInfo = new FileInfo(fullPath);
|
|
var contentType = GetContentType(fileInfo.Name);
|
|
|
|
var response = new HttpResponseMessage(HttpStatusCode.OK)
|
|
{
|
|
Content = new StreamContent(new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
|
};
|
|
response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
|
|
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline")
|
|
{
|
|
FileName = fileInfo.Name
|
|
};
|
|
|
|
return ResponseMessage(response);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Ok(new { success = false, message = "下载文件失败:" + ex.Message });
|
|
}
|
|
}
|
|
}
|
|
}
|