1. Введение
При разработке интерфейса нам иногда хочется сделатьИнтерфейс может быть запрошен только конкретным человеком (источник), то вам необходимо проверить параметры запроса на стороне сервера.
В этом случае мы можем использоватьinterceptor
Чтобы единообразно выполнять проверку параметров, но при наличии множества интерфейсов с разными значениями настроек мы не можем написать многоinterceptor
, а потом добавить их по одному по пути?
Перед лицом этой ситуации мы можем выбрать настроить аннотацию, сообщите нам аннотациями, который является посетителем, разрешенным этим интерфейсом.
Примечание: В примере в этой статье проверяется только одно поле, а безопасность не высока.В реальных проектах для обеспечения безопасности может использоваться многополевое шифрование, и принцип тот же, что и в тексте.
2. Введение в аннотации Java
Java Annotation — это механизм аннотаций, представленный в JDK5.0.
Аннотация — это специальный тег в коде, эти теги можно прочитать во время компиляции, загрузки класса, во время выполнения и выполнить соответствующую обработку.
Используя аннотацию, программисты могут встраивать некоторую дополнительную информацию в исходные файлы без изменения исходной логики.
Аннотация может использоваться как модификаторы, которые могут быть использованы для пакета, класса, интерфейса, конструктора, метода, переменной элементов, параметра, локальной переменной (локальной переменной), аннотации, JDK 1.8, до тех пор, пока тип (включая классы, интерфейсы, Аннотации, перечисление) можно использовать.
Мы можем использовать JDK и Annotation Другие рамки, вы также можете настроить аннотацию.
3. Мета-аннотация
Что такое мета-аннотации В моем понимании, мета-аннотации официально предоставляются java и используются для изменения некоторых свойств других аннотаций.
Поскольку пользовательские аннотации открыты, все аннотации должны иметь правила, которым нужно следовать, и некоторые их свойства должны быть определены. Например: где используется эта аннотация? Класс, метод или поле? Жизненный цикл этой аннотации: Что? Лучше? сохранить его в исходном коде для чтения или он будет сгенерирован в файле класса, чтобы иметь фактическое влияние на программу?Все это необходимо определить заранее, поэтому есть:
Эти четыре мета-аннотации @Target, @Retation, @Inherited, @Documented.
Далее четыре мета-аннотации объясняются одна за другой.
@Target
Используется для описания области применения аннотации (т. е.: где можно использовать описанную аннотацию)
Его перечисление определяет диапазон классов JDKElementType
, а его значения следующие:
- CONSTRUCTOR: используется для описания конструктора
- FIELD: используется для описания домена, который является переменной-членом класса.
- LOCAL_VARIABLE: используется для описания локальных переменных.
- МЕТОД: используется для описания метода
- ПАКЕТ: используется для описания пакета
- ПАРАМЕТР: используется для описания параметров
- ТИП: используется для описания классов, интерфейсов (включая типы аннотаций) или объявлений перечисления.
Примечание. В JDK1.8 добавлено два новых типа:8. TYPE_PARAMETER: указывает, что эту аннотацию можно использовать перед объявлением типа, 9. TYPE_USE указывает, что эту аннотацию можно использовать во всех местах, где используется тип.
@Retention
Указывает, на каком уровне должна быть сохранена информация аннотации для описания жизненного цикла аннотации (т. е.: в какой области действительна описанная аннотация)
Его диапазон значений исходит из класса перечисленияRetentionPolicy
Значения следующие:
- Источник: Действителен в исходном файле (т.е. исходный файл зарезервирован)
- КЛАСС: Действителен в файлах класса (т.е. сохранение класса)
- ВРЕМЯ ВЫПОЛНЕНИЯ: Действителен во время выполнения (т. е. зарезервировано во время выполнения)
@Documented
@Documented используется для описания общедоступного API, что другие типы аннотаций должны использоваться в качестве аннотированных членов программы, и, таким образом, могут быть задокументированы такими инструментами, как javadoc. Documented — это аннотация разметки без членов.
@Inherited
Мета-аннотация @Inherited — это аннотация разметки, @Inherited указывает, что аннотированный тип наследуется. Если в классе используется тип аннотации @Inherited, аннотация будет использоваться в подклассах этого класса.
4. Общие примечания
Обычно используемые сторонние фреймворки реализуют множество аннотаций, таких какMybatis
изParam
,Spring
изComponent
,Service
,fastjson
изJSONfield
и Т. Д.
Конкретный метод реализации здесь не объясняется, и заинтересованные друзья могут посмотретьfastjson
Исходный код проекта по сравнению сspring
Другие фреймворки, более простые и понятные.
Увидев такую аннотацию или простую или сложную функцию, можем ли мы также реализовать ее самостоятельно?
5. Индивидуальные аннотации
5.1 Определение аннотаций
Сначала давайте определим аннотацию:
package com.huyan.demo.config;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* created by huyanshi on 2019/1/20
*/
@Target(ElementType.METHOD) // 该注解使用在方法上
@Retention(RetentionPolicy.RUNTIME) //运行时注解
@Documented
public @interface CheckSource {
//该注解的参数,是一个string数组
String[] sources() default {"all"};
}
Нужная нам аннотация предназначена для проверки параметров, поэтому область ее использования方法
, жизненный цикл运行时保留
Кроме того, аннотация имеет видstring数组
Параметры, используемые для представления списка источника, разрешенные текущим методом.
5.2 Написание парсера аннотаций
На самом деле, я сначала долго бился здесь, потому что не мог понять一个注解应该在哪里以什么方式调用
.
По моему мнению, каждая аннотация должна иметь поле (или что-то в этом роде), указывающее, что она должна идти в哪里
Вызовите реальное использование этой аннотации.
Позже, хорошенько подумав, я обнаружил, что это нереально, потому что функция аннотаций совершенно нестандартная, можно реализовать любую функцию, которую вы хотите, возвращаемым значением может быть любое значение, а логика внутри тоже произвольная.
Тогда это означает, что вам нужно нести ответственность за свои аннотации, иначе это не имеет никакого эффекта.То есть вам нужно писать свои аннотации注解解析器
, определять什么时候用到这个注解,用它干什么
?
@Чисто личное мнение, смотрите внимательно
Полазив по интернету, я обнаружил, что основной形式
Есть три вида:
1.interceptor
Этот способ удобнее, можно напрямую перехватывать все запросы, проверять, есть ли конкретные аннотации по классам и методам, введенным запросом, и как действовать, если они есть.
Но ограничения относительно велики, и мы не только используем аннотации в контроллере.
2.AOP
Этот метод также более удобен и имеет лучшую масштабируемость.Когда вам нужно использовать аннотацию в новом месте, просто добавьте новый pointcut.
3. Инкапсулируйте его в метод и вызывайте его в любое время
Это то, что нравится большинству людей (на самом деле, наиболее популярно писать это каждый раз, когда вы его используете), но если вы не будете часто рефакторить код, вы обнаружите, что экспорт заполнен кодом, который вы использовать для определенной аннотации, то это очень сбой, вам нужно максимально инкапсулировать его, поместить в унифицированный класс инструментов и вызывать его каждый раз, когда он вам нужен.
@Личное мнение закончилось!
Так как наша потребность на этот раз в перехвате нелегальных запросов, конечно же, первый способ надежнее, поэтому мы написали перехватчик:
package com.huyan.demo.config;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
/**
* created by huyanshi on 2019/1/20
*/
public class CheckSourceInterceptor extends HandlerInterceptorAdapter {
private static Logger LOG = LoggerFactory.getLogger(CheckSourceInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (!(handler instanceof HandlerMethod)) {
LOG.warn("UnSupport handler");
throw new IllegalArgumentException("Interceptor only supports HandlerMethod handler");
}
//拿到请求参数里面的source参数
String source = request.getParameter("source");
String errorMsg = null;
//如果source为空,返回错误
if (null == source || "".equals(source)) {
errorMsg = "No source in params";
}
if (errorMsg != null) {
response.setStatus(500);
LOG.info(errorMsg);
response.getWriter().write(errorMsg);
return false;
}
//拿到该方法上的注解对象
CheckSource checkSource = getCheckSource((HandlerMethod) handler);
//如果拿到的对象为空,说明没有此注解,直接放行
if (checkSource != null) {
//拿到注解对象的属性,即允许通行的source列表
String[] sources = checkSource.sources();
if (sources.length == 0 || sources[0].equals("all")) {
//列表为空或者为默认值,放行
return true;
}
//遍历列表,如果传入的参数在其中,则放行
for (String s : sources) {
if (s.equals(source)) {
return true;
}
}
//如果传入的source参数不在允许的参数列表中,则拦截请求,并返回错误信息
errorMsg = "source is not support";
response.getWriter().write(errorMsg);
return false;
}
return true;
}
/**
* 拿到该方法上的checksource注解对象
*/
private CheckSource getCheckSource(HandlerMethod handlerMethod) {
if (handlerMethod.getBeanType().isAnnotationPresent(CheckSource.class)) {
return handlerMethod.getBeanType().getAnnotation(CheckSource.class);
} else if (handlerMethod.getMethod().isAnnotationPresent(CheckSource.class)) {
return handlerMethod.getMethod().getAnnotation(CheckSource.class);
}
return null;
}
}
В код добавлены более подробные комментарии, вот только общая идея:
Через механизм перехватчика получить метод по методуCheckSource
объект, объект может быть пустым, получить его значение, когда он не пустsources
свойства, а затем, в свою очередь, пройти, чтобы определить, находится ли входящий источник в списке разрешенных.
В этом перехватчике мы определяем:
1. Когда использовать эту аннотацию?
В нашей конфигурации при использовании этого перехватчика при входе метод слоя контроллера.
2. Как пользоваться этой аннотацией?
принимать входящиеsource
Параметры и свойства этой аннотацииsources
Список совпадает один за другим. Если есть совпадение, запрос разрешается, а если нет совпадающего значения, возвращается сообщение об ошибке.
5.3 Фактическое использование аннотаций
5.3.1 Сначала настройте этот перехватчик, перехватstatus
интерфейс
package com.huyan.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* created by huyanshi on 2019/1/20
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
CheckSourceInterceptor checkSourceInterceptor = new CheckSourceInterceptor();
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(checkSourceInterceptor).addPathPatterns("/status");
}
}
5.3.2. интерфейс состояния
package com.huyan.demo.controller;
import com.huyan.demo.config.CheckSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* created by pfliu on 2018/9/2
*/
@RestController
public class StatusController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@CheckSource(sources = {"huyan", "huihui"})
@GetMapping(value = "/status")
public Object status(@RequestParam("source") String source) {
return "哈哈哈";
}
}
Хорошо, кодирование завершено.
Запустите проект и посмотрите на результаты.
5.3.3 Результаты испытаний
- Без
source
параметр
- Неправильно
source
параметр
- правильный
source
параметр
6. Резюме
Механизм аннотирования java не так уж сложен для понимания, но дело в том, что нам трудно думать о его применении в нашей повседневной жизни, во-первых, потому, что мы с ним не знакомы, а во-вторых, это наша проблема.业务
, нет такой общей логики.
Механизм аннотации широко используется в различных фреймворках, что достаточно, чтобы доказать, что это отличный механизм, достойный нашего изучения и применения в нашей собственной работе.
7. Справочные ссылки
Джош-настойчивость.ITeye.com/blog/222649… Woohoo. IBM.com/developer Я…
Заканчивать.
ChangeLog
20.01.2019 ЗавершеноВсе вышеизложенное является личными мыслями, если есть какие-либо ошибки, пожалуйста, исправьте их в комментариях.
Добро пожаловать на перепечатку, пожалуйста, подпишите и сохраните исходную ссылку.
Контактный адрес электронной почты: huyanshi2580@gmail.com
Дополнительные заметки об обучении см. в личном блоге ------>Хуян тен